루아 레퍼런스 매뉴얼 — C API
루아 레퍼런스 매뉴얼 — C API (The Application Program Interface)
이 자료는 공식 Lua 5.4 Reference Manual의 **챕터 4 — The Application Program Interface (애플리케이션 프로그램 인터페이스, 이하 C API)**를 한국어로 옮기고 정리한 번역·수집본이에요. 루아를 C 프로그램에 임베딩해서 쓸 때(또는 C 함수를 루아로 익스포트할 때) 필요한 모든 것이 이 장에 담겨 있어요.
이 장의 구성은 이래요. 먼저 C와 루아가 값을 주고받는 가상 스택부터 보고(§4.1), 그다음 C 클로저(§4.2)와 레지스트리(§4.3), C 쪽에서의 오류 처리(§4.4)와 yield 처리(§4.5)를 다뤄요. 그리고 §4.6에서 C API의 모든 함수와 타입을 알파벳 순서로 나열하고, 마지막 §4.7에서 디버그 인터페이스를 설명해요.
번역의 정확성을 위해 C 코드와 함수 시그니처(예: int lua_gettop (lua_State *L);)는 원문 바이트를 그대로 보존했어요. 코드 펜스(c ) 안의 내용은 모두 원문입니다.
출처: Lua 5.4 Reference Manual, Chapter 4 — The Application Program Interface (https://www.lua.org/manual/5.4/manual.html) · 원문 저작권은 Lua.org에 있으며, 본 자료는 학습·수집 목적의 비공식 한국어 번역입니다.
본문
4 — The Application Program Interface (애플리케이션 프로그램 인터페이스)
이 장에서는 루아의 C API를 설명해요. 쉽게 말하면 호스트 프로그램이 루아와 대화할 때 쓰는 C 함수의 모음이죠. 모든 API 함수와 관련 타입, 상수는 헤더 파일 lua.h에 선언되어 있어요.
여기에서는 '함수'라는 표현을 쓰지만, API의 어떤 기능도 매크로로 제공될 수 있어요. 별도의 언급이 없으면 그런 매크로들은 각 인자를 정확히 한 번씩만 사용해요(첫 번째 인자, 즉 항상 루아 상태인 그 인자는 예외이지만요). 그래서 숨겨진 부작용이 생기지 않아요.
대부분의 C 라이브러리와 마찬가지로 루아 API 함수들은 인자의 유효성이나 일관성을 검사하지 않아요. 물론 이 동작을 바꾸고 싶다면 매크로 LUA_USE_APICHECK를 정의한 채로 루아를 컴파일하면 돼요.
루아 라이브러리는 완전히 재진입(reentrant)이 가능해요. 전역 변수가 전혀 없고, 필요한 정보를 모두 루아 상태(Lua state)라는 동적 구조에 담아두거든요.
각 루아 상태에는 스레드가 하나 이상 있어요. 스레드는 서로 독립적이면서도 협력적으로 실행되는 실행 흐름을 뜻해요. 이름과 달리 lua_State 타입이 가리키는 건 바로 이 스레드예요. (스레드를 통해서 그 스레드와 연결된 루아 상태를 간접적으로 가리키기도 하고요.)
라이브러리의 모든 함수는 lua_newstate를 제외하면 첫 번째 인자로 항상 스레드의 포인터를 받아요. lua_newstate는 처음부터 루아 상태를 만들어 새 상태의 메인 스레드 포인터를 돌려주는 함수라서 예외예요.
4.1 — The Stack (스택)
루아는 C와 값을 주고받을 때 가상 스택(virtual stack)을 사용해요. 이 스택의 각 요소는 루아 값 하나(nil, 숫자, 문자열 등)를 나타내요. API 함수들은 받은 루아 상태 매개변수를 통해서 이 스택에 접근할 수 있어요.
루아가 C 함수를 호출할 때마다 그 C 함수는 새 스택을 받아요. 이 스택은 이전 스택이나 아직 살아 있는 다른 C 함수의 스택과 독립적이죠. 이 스택에는 처음에 그 C 함수의 인자들이 들어 있고, C 함수는 여기에 임시 루아 값을 저장하거나, 호출자에게 돌려줄 결과를 쌓아야 해요(lua_CFunction 참고).
편의를 위해 API의 대부분 조회 연산은 엄격한 스택 규율을 따르지 않아요. 대신 인덱스(index)로 스택의 아무 요소나 가리킬 수 있어요. 양수 인덱스는 스택의 절대 위치를 나타내는데, 1이 스택의 바닥이에요. 음수 인덱스는 스택의 꼭대기에서부터의 상대 위치를 나타내죠. 조금 더 정확히 말하면 스택에 n개의 요소가 있을 때 인덱스 1은 첫 번째 요소(즉 가장 먼저 스택에 쌓인 요소)를, 인덱스 n은 마지막 요소를 가리켜요. 인덱스 -1도 마지막 요소(즉 맨 위 요소)를, 인덱스 -n은 첫 번째 요소를 가리키고요.
4.1.1 — Stack Size (스택 크기)
루아 API를 다룰 때 일관성을 유지하는 건 여러분의 몫이에요. 특히 스택 넘침(overflow)을 제어할 책임도 여러분에게 있어요. 어떤 API 함수를 호출할 때는 그 결과를 담을 공간이 스택에 충분한지 반드시 확인해야 해요.
위 규칙에는 예외가 하나 있어요. 결과 개수를 고정하지 않고 루아 함수를 호출하면(lua_call 참고) 루아가 모든 결과를 담을 공간을 스택에 확보해 줘요. 하지만 그 이상의 여유 공간은 보장하지 않아요. 그래서 그런 호출 뒤에 스택에 뭔가를 더 쌓으려면 lua_checkstack을 사용해야 해요.
루아가 C 함수를 호출할 때마다 스택에 최소 LUA_MINSTACK개의 추가 요소 공간을 확보해 줘요. 즉 최대 LUA_MINSTACK개의 값을 안전하게 스택에 쌓을 수 있다는 뜻이에요. LUA_MINSTACK은 20으로 정의되어 있어서, 루프로 스택에 요소를 쌓는 상황이 아니라면 대개 스택 공간을 걱정할 필요가 없어요. 필요할 때는 lua_checkstack 함수로 새 요소를 쌓을 공간이 충분한지 확인하면 돼요.
4.1.2 — Valid and Acceptable Indices (유효 인덱스와 허용 인덱스)
API에서 스택 인덱스를 받는 함수들은 유효 인덱스(valid index)나 허용 인덱스(acceptable index)만 다뤄요.
유효 인덱스는 수정 가능한 루아 값이 저장된 위치를 가리키는 인덱스예요. 스택 꼭대기와 1 사이의 인덱스(1 ≤ abs(index) ≤ top)에 더해, 의사 인덱스(pseudo-index)도 포함해요. 의사 인덱스는 C 코드가 접근할 수는 있지만 실제로 스택에는 없는 위치를 나타내는데, 레지스트리(§4.3)와 C 함수의 업밸류(§4.2)에 접근할 때 사용해요.
특정 위치를 반드시 수정할 필요 없이 값만 필요한 함수(예: 조회 함수)는 허용 인덱스로 호출할 수 있어요. 허용 인덱스는 모든 유효 인덱스를 포함하고, 또 스택에 할당된 공간 안이라면 스택 꼭대기 뒤쪽의 양수 인덱스, 즉 스택 크기까지의 인덱스도 포함해요. (0은 절대 허용 인덱스가 아니라는 점에 주의하세요.) 현재 C 함수의 실제 업밸류 개수보다 큰 업밸류 인덱스(§4.2)도 유효하진 않지만 허용되요. 별도 언급이 없으면 API 함수들은 허용 인덱스로 동작해요.
허용 인덱스가 있는 덕분에 스택을 조회할 때 굳이 스택 꼭대기를 기준으로 한 추가 검사를 하지 않아도 돼요. 예를 들어 C 함수가 세 번째 인자를 조회할 때, 세 번째 인자가 실제로 있는지(즉 3이 유효 인덱스인지) 확인할 필요 없이 바로 조회할 수 있어요.
허용 인덱스로 호출할 수 있는 함수들은, 유효하지 않은 인덱스를 마치 가상 타입 LUA_TNONE의 값을 담고 있는 것처럼 취급해요. LUA_TNONE은 nil처럼 동작하죠.
4.1.3 — Pointers to strings (문자열 포인터)
여러 API 함수는 스택에 있는 루아 문자열을 가리키는 포인터(const char*)를 돌려줘요. (lua_pushfstring, lua_pushlstring, lua_pushstring, lua_tolstring을 보세요. 보조 라이브러리의 luaL_checklstring, luaL_checkstring, luaL_tolstring도 참고하세요.)
일반적으로 루아의 가비지 컬렉션은 내부 메모리를 해제하거나 옮길 수 있어서, 내부 문자열을 가리키던 포인터가 무효가 될 수 있어요. 이 포인터를 안전하게 쓰도록 API는 보장을 하나 걸어둡니다. 스택 인덱스에 있는 문자열 포인터는, 그 인덱스의 문자열 값이 스택에서 제거되지 않는 한 유효해요. (다른 인덱스로 옮겨질 수는 있지만요.) 그 인덱스가 의사 인덱스(업밸류를 가리키는)라면, 해당 호출이 활성화되어 있고 해당 업밸류가 수정되지 않는 동안 포인터가 유효해요.
디버그 인터페이스의 몇몇 함수도 문자열 포인터를 돌려줘요. 바로 lua_getlocal, lua_getupvalue, lua_setlocal, lua_setupvalue인데요. 이 함수들의 포인터는 호출한 함수가 활성화되어 있고, 주어진 클로저(주어졌다면)가 스택에 있는 동안 유효하다고 보장돼요.
이런 보장만 제외하면 가비지 컬렉터는 내부 문자열을 가리키는 어떤 포인터든 무효화할 수 있어요.
4.2 — C Closures (C 클로저)
C 함수를 만들 때 그 함수에 몇몇 값을 함께 묶어줄 수 있어요. 그렇게 만들어진 게 C 클로저(C closure)예요(lua_pushcclosure 참고). 이렇게 묶인 값들을 업밸류(upvalue)라고 부르고, 함수가 호출될 때마다 접근할 수 있어요.
C 함수가 호출되면 그 업밸류들은 특정 의사 인덱스에 위치해요. 이 의사 인덱스는 매크로 lua_upvalueindex가 만들어 줘요. 함수에 묶인 첫 번째 업밸류는 lua_upvalueindex(1)에 있고, 그다음은 차례로 이어져요. lua_upvalueindex(*n*)에 접근할 때 n이 현재 함수의 업밸류 개수보다 크면(그래도 256 이하일 때, 256은 클로저의 최대 업밸류 개수에 1을 더한 값이에요) 허용은 되지만 유효하지 않은 인덱스가 만들어져요.
C 클로저는 자기 업밸류의 값을 바꿀 수도 있어요.
4.3 — Registry (레지스트리)
루아는 레지스트리(registry)를 제공해요. 어떤 C 코드든 필요로 하는 루아 값을 저장해 둘 수 있는 미리 정의된 테이블이죠. 레지스트리 테이블은 항상 의사 인덱스 LUA_REGISTRYINDEX로 접근할 수 있어요. 어떤 C 라이브러리든 이 테이블에 데이터를 저장할 수 있지만, 다른 라이브러리와 충돌하지 않도록 다른 라이브러리가 쓰는 키와는 다른 키를 고르는 데 신경 써야 해요. 보통 키로는 자기 라이브러리 이름이 담긴 문자열, 코드 안 C 객체의 주소를 가진 라이트 유저데이터, 아니면 자기 코드가 만든 루아 객체를 쓰는 게 좋아요. 변수 이름과 마찬가지로 밑줄 다음에 대문자가 오는 문자열 키는 루아 전용으로 예약되어 있어요.
레지스트리의 정수 키는 참조 메커니즘(luaL_ref 참고)과 몇몇 미리 정의된 값에 사용돼요. 그래서 레지스트리의 정수 키를 다른 목적으로 쓰면 안 돼요.
새 루아 상태를 만들면 레지스트리에는 미리 정의된 값이 몇 개 딸려와요. 이 값들은 lua.h에 상수로 정의된 정수 키로 인덱싱돼요. 정의된 상수는 다음과 같아요.
-
LUA_RIDX_MAINTHREAD: 이 인덱스에 상태의 메인 스레드가 있어요. (메인 스레드는 상태와 함께 만들어지는 그 스레드예요.)
-
LUA_RIDX_GLOBALS: 이 인덱스에 전역 환경이 있어요.
4.4 — Error Handling in C (C에서의 오류 처리)
내부적으로 루아는 오류를 처리할 때 C의 longjmp를 사용해요. (C++로 컴파일하면 예외를 쓰기도 해요. 자세한 건 소스 코드에서 LUAI_THROW를 찾아보세요.) 루아는 메모리 할당 오류나 타입 오류 같은 어떤 오류와 마주치면 오류를 던지고(raise), 즉 long jump를 해요. 보호 환경(protected environment)은 setjmp로 복구 지점을 설정해서, 어떤 오류든 가장 최근의 활성 복구 지점으로 점프하게 해요.
C 함수 안에서는 lua_error를 호출해서 오류를 명시적으로 던질 수도 있어요.
대부분의 API 함수는 예를 들어 메모리 할당 오류 때문에 오류를 던질 수 있어요. 각 함수의 문서는 그 함수가 오류를 던질 수 있는지 여부를 알려줘요.
보호 환경 밖에서 오류가 발생하면 루아는 패닉 함수(panic function, lua_atpanic 참고)를 호출한 뒤 abort를 호출해서 호스트 애플리케이션을 종료해요. 패닉 함수가 리턴하지 않으면(예: 루아 밖의 자기 복구 지점으로 long jump를 하면) 이 종료를 피할 수 있어요.
패닉 함수는 말 그대로 최후의 수단이에요. 프로그램은 이것을 피해야 해요. 일반적인 규칙으로, 루아 상태를 받아 루아가 호출한 C 함수라면 그 루아 상태에 무엇을 하든 괜찮아요. 이미 보호되어 있을 테니까요. 하지만 C 코드가 다른 루아 상태를 다룰 때는(예: 함수의 루아 상태 인자, 레지스트리에 저장된 루아 상태, lua_newthread의 결과), 그 상태는 오류를 던질 수 없는 API 호출에서만 사용해야 해요.
패닉 함수는 메시지 핸들러인 것처럼 실행돼요(§2.3). 특히 오류 객체가 스택 꼭대기에 있어요. 다만 스택 공간에 대한 보장은 없어요. 스택에 무엇이든 쌓으려면 패닉 함수는 먼저 사용 가능한 공간을 확인해야 해요(§4.1.1).
4.4.1 — Status Codes (상태 코드)
API에서 오류를 보고하는 몇몇 함수는 다음과 같은 상태 코드로 서로 다른 종류의 오류나 조건을 나타내요.
-
LUA_OK (0): 오류 없음.
-
LUA_ERRRUN: 런타임 오류.
-
LUA_ERRMEM: 메모리 할당 오류. 이런 오류에는 루아가 메시지 핸들러를 호출하지 않아요.
-
LUA_ERRERR: 메시지 핸들러를 실행하는 중에 발생한 오류.
-
LUA_ERRSYNTAX: 사전 컴파일 중 발생한 문법 오류.
-
LUA_YIELD: 스레드(코루틴)가 yield 했음.
-
LUA_ERRFILE: 파일 관련 오류. 예를 들어 파일을 열거나 읽지 못한 경우예요.
이 상수들은 헤더 파일 lua.h에 정의되어 있어요.
4.5 — Handling Yields in C (C에서의 yield 처리)
내부적으로 루아는 코루틴을 yield 할 때도 C의 longjmp를 사용해요. 그래서 C 함수 foo가 어떤 API 함수를 호출했는데 그 API 함수가 yield 하면(직접, 또는 yield 하는 함수를 호출하는 걸 통해서 간접적으로) 루아는 더 이상 foo로 돌아갈 수 없어요. longjmp가 foo의 프레임을 C 스택에서 지워 버리기 때문이죠.
이런 문제를 피하기 위해 루아는 API 호출을 가로질러 yield 하려고 하면 오류를 던져요. 단 세 함수는 예외인데, lua_yieldk, lua_callk, lua_pcallk예요. 이 함수들은 모두 yield 이후에 실행을 이어갈 연속 함수(continuation function, k라는 매개변수)를 받아요.
연속 함수를 설명하려면 용어를 먼저 정리할게요. 루아가 호출한 C 함수가 있고 이걸 원래 함수(original function)라고 부를게요. 이 원래 함수가 C API의 그 세 함수 중 하나를 호출하는데, 그걸 피호출 함수(callee function)라고 해요. 피호출 함수가 현재 스레드를 yield 하면, 즉 피호출 함수가 lua_yieldk이거나, 피호출 함수가 lua_callk/lua_pcallk인데 그들이 호출한 함수가 yield 하는 경우죠.
실행 중인 스레드가 피호출 함수를 실행하다가 yield 한다고 해볼게요. 스레드가 재개된 뒤 결국 피호출 함수를 끝까지 실행하게 돼요. 그런데 피호출 함수는 원래 함수로 돌아갈 수 없어요. yield 때문에 피호출 함수의 C 스택 프레임이 파괴됐거든요. 대신 루아는 피호출 함수에 인자로 주어졌던 연속 함수를 호출해요. 이름이 말해 주듯 연속 함수는 원래 함수가 하던 일을 이어서 해야 해요.
예시로 다음 함수를 볼게요.
int original_function (lua_State *L) {
... /* code 1 */
status = lua_pcall(L, n, m, h); /* calls Lua */
... /* code 2 */
}
이제 lua_pcall이 실행하는 루아 코드가 yield 할 수 있게 만들고 싶어요. 먼저 함수를 이렇게 다시 써볼게요.
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이 실행 중인 코드가 오류를 내거나 yield 해서) 중단되면 루아가 k를 호출해야 한다는 걸 루아에게 알려야 해요. 그래서 lua_pcall을 lua_pcallk로 바꿔서 코드를 이렇게 다시 써요.
int original_function (lua_State *L) {
... /* code 1 */
return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
}
연속 함수를 외부에서 명시적으로 호출한다는 점에 주목하세요. 루아는 필요한 경우에만, 즉 오류가 났거나 yield 뒤에 재개될 때만 연속 함수를 호출해요. 호출한 함수가 yield 없이 정상적으로 리턴하면 lua_pcallk(와 lua_callk)도 정상적으로 리턴해요. (물론 그 경우에 연속 함수를 호출하는 대신 원래 함수 안에서 똑같은 일을 직접 해도 돼요.)
연속 함수는 루아 상태 말고도 두 가지 매개변수를 더 받아요. 하나는 호출의 최종 상태, 다른 하나는 lua_pcallk에 처음 전달했던 컨텍스트 값(ctx)이에요. 루아는 이 컨텍스트 값을 사용하지 않아요. 원래 함수에서 연속 함수로 값을 그저 넘겨줄 뿐이에요. lua_pcallk의 상태는 lua_pcallk가 리턴했을 값과 같아요. 단 yield 뒤에 실행될 때는 LUA_OK 대신 LUA_YIELD라는 점만 달라요. lua_yieldk와 lua_callk는 루아가 연속 함수를 호출할 때 상태가 항상 LUA_YIELD예요. (이 두 함수는 오류를 처리하지 않기 때문에, 오류가 나면 루아가 연속 함수를 호출하지 않아요.) 마찬가지로 lua_callk를 쓸 때는 상태를 LUA_OK로 해서 연속 함수를 호출해야 해요. (lua_yieldk는 보통 리턴하지 않기 때문에 연속 함수를 직접 호출해 봐야 별 의미가 없어요.)
루아는 연속 함수를 마치 원래 함수인 것처럼 취급해요. 연속 함수는 원래 함수와 같은 루아 스택을, 피호출 함수가 리턴했을 때와 같은 상태로 받아요. (예를 들어 lua_callk 뒤에는 함수와 인자가 스택에서 제거되고 호출 결과로 대체돼요.) 연속 함수는 같은 업밸류도 가져요. 연속 함수가 리턴하는 것은 원래 함수의 리턴인 것처럼 루아가 처리해요.
4.6 — Functions and Types (함수와 타입)
여기서는 C API의 모든 함수와 타입을 알파벳 순서로 나열할게요. 각 함수에는 이런 표시가 붙어 있어요. [-o, +p, *x*]
첫 번째 필드 o는 함수가 스택에서 pop 하는 요소 개수예요. 두 번째 필드 p는 함수가 스택에 push 하는 요소 개수죠. (함수는 항상 인자를 pop 한 뒤에 결과를 push 해요.) x|y 형태의 필드는 상황에 따라 x개나 y개를 push(또는 pop) 한다는 뜻이에요. 물음표 '?'는 인자만 봐서는 함수가 몇 개를 pop/push 하는지 알 수 없다는 뜻이에요. (예를 들어 스택에 뭐가 들어 있느냐에 달려 있을 수 있어요.) 세 번째 필드 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과 비슷하지만 완전히 같지는 않은 기능을 제공해야 해요. 인자는 다음과 같아요. ud는 lua_newstate에 넘겨진 불투명 포인터, ptr은 할당/재할당/해제되는 블록을 가리키는 포인터, osize는 블록의 원래 크기이거나 지금 할당하려는 것이 무엇인지에 대한 일종의 코드, nsize는 블록의 새 크기예요.
ptr이 NULL이 아니면 osize는 ptr이 가리키는 블록의 크기, 즉 할당하거나 재할당할 때 주어진 크기예요.
ptr이 NULL이면 osize는 루아가 지금 할당하려는 객체의 종류를 나타내요. osize가 LUA_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; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
참고로 ISO C는 free(NULL)이 아무 효과가 없고 realloc(NULL,size)이 malloc(size)과 동등하다는 것을 보장해요.
lua_arith
[-(2|1), +1, e]
void lua_arith (lua_State *L, int op);
스택 꼭대기에 있는 두 값(부정 연산의 경우 한 값)에 산술 또는 비트 연산을 수행해요. 꼭대기 값이 두 번째 피연산자예요. 이 값들을 pop 하고 연산 결과를 push 해요. 함수는 해당 루아 연산자의 의미론을 따르므로(즉 메타메서드를 호출할 수 있어요) 메타메서드를 호출할 수 있어요.
op의 값은 다음 상수 중 하나여야 해요.
-
LUA_OPADD: 덧셈(+) 수행
-
LUA_OPSUB: 뺄셈(-) 수행
-
LUA_OPMUL: 곱셈(*) 수행
-
LUA_OPDIV: 실수 나눗셈(/) 수행
-
LUA_OPIDIV: 바닥 나눗셈(//) 수행
-
LUA_OPMOD: 나머지(%) 수행
-
LUA_OPPOW: 거듭제곱(^) 수행
-
LUA_OPUNM: 수학적 부정(단항 -) 수행
-
LUA_OPBNOT: 비트 NOT(~) 수행
-
LUA_OPBAND: 비트 AND(&) 수행
-
LUA_OPBOR: 비트 OR(|) 수행
-
LUA_OPBXOR: 비트 배타적 OR(~) 수행
-
LUA_OPSHL: 왼쪽 시프트(>) 수행
-
LUA_OPSHR: 오른쪽 시프트(>>) 수행
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 메타메서드를 존중해요. 그래서 여기서 '함수'란 호출 가능한 어떤 값이든 뜻해요.
호출을 하려면 다음 프로토콜을 따라야 해요. 먼저 호출할 함수를 스택에 push 하고, 그다음 호출 인자들을 순서대로, 즉 첫 인자를 가장 먼저 push 해요. 마지막으로 lua_call을 호출하는데, nargs는 스택에 push 한 인자의 개수예요. 함수가 리턴하면 모든 인자와 함수 값이 pop 되고 호출 결과가 스택에 push 돼요. 결과 개수는 nresults로 맞춰지는데, nresults가 LUA_MULTRET이면 예외예요. 그 경우 함수의 모든 결과가 push 되는데, 루아가 리턴 값들이 스택 공간에 들어가게는 하지만 추가 공간은 보장하지 않아요. 함수 결과는 순서대로 push 되는데(첫 결과가 먼저), 그래서 호출 뒤에는 마지막 결과가 스택 꼭대기에 있어요.
함수를 호출하고 실행하는 동안 발생한 어떤 오류든(longjmp로) 위로 전파돼요.
다음 예시는 호스트 프로그램이 이 루아 코드와 같은 일을 어떻게 하는지 보여줘요.
a = f("how", t.x, 14)
C로는 이렇게 됩니다.
lua_getglobal(L, "f"); /* function to be called */
lua_pushliteral(L, "how"); /* 1st argument */
lua_getglobal(L, "t"); /* table to be indexed */
lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
lua_remove(L, -2); /* remove 't' from the stack */
lua_pushinteger(L, 14); /* 3rd argument */
lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
lua_setglobal(L, "a"); /* set global '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과 완전히 똑같이 동작하지만, 호출된 함수가 yield 할 수 있어요(§4.5).
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 함수의 타입이에요.
루아와 제대로 소통하려면 C 함수는 매개변수와 결과를 주고받는 방식을 정하는 다음 프로토콜을 따라야 해요. C 함수는 루아에서 온 인자를 스택에 순서대로 받아요(첫 인자가 먼저 push 됨). 그래서 함수가 시작될 때 lua_gettop(L)은 함수가 받은 인자의 개수를 리턴해요. 첫 인자(있다면)는 인덱스 1에, 마지막 인자는 lua_gettop(L)에 있어요. 루아에 값을 돌려주려면 C 함수는 결과를 스택에 순서대로 push 하고(첫 결과 먼저) C에서 결과 개수를 리턴하면 돼요. 결과 아래 스택에 있던 다른 값은 루아가 알아서 버려줘요. 루아 함수처럼, 루아가 호출한 C 함수도 여러 결과를 리턴할 수 있어요.
예를 들어 다음 함수는 가변 개수의 숫자 인자를 받아 평균과 합계를 리턴해요.
static int foo (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
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); /* first result */
lua_pushnumber(L, sum); /* second result */
return 2; /* number of results */
}
lua_checkstack
[-0, +0, –]
int lua_checkstack (lua_State *L, int n);
스택에 최소 n개의 추가 요소 공간이 있는지, 즉 최대 n개의 값을 안전하게 쌓을 수 있는지 확인해요. 요청을 처리할 수 없으면 false를 리턴하는데, 그 이유는 스택이 고정 최대 크기(보통 최소 수천 요소)보다 커지기 때문이거나, 추가 공간용 메모리를 할당할 수 없기 때문이에요. 이 함수는 스택을 절대 줄이지 않아요. 스택에 이미 추가 요소 공간이 있으면 그대로 두고요.
lua_close
[-0, +0, –]
void lua_close (lua_State *L);
메인 스레드의 모든 활성 to-be-closed 변수를 닫고, 주어진 루아 상태의 모든 객체를 해제하며(해당 가비지 컬렉션 메타메서드가 있다면 호출), 이 상태가 사용한 모든 동적 메모리를 비워요.
여러 플랫폼에서는 이 함수를 호출할 필요가 없을 수도 있어요. 호스트 프로그램이 끝나면 모든 자원이 자연히 해제되거든요. 반면 데몬이나 웹 서버처럼 여러 상태를 만드는 오래 실행되는 프로그램이라면 상태가 더 이상 필요 없어지는 즉시 닫아야 할 거예요.
lua_closeslot
[-0, +0, e]
void lua_closeslot (lua_State *L, int index);
주어진 인덱스의 to-be-closed 슬롯을 닫고 그 값을 nil로 설정해요. 인덱스는 이전에 닫도록 표시된 슬롯들(lua_toclose 참고) 중 아직 활성(즉 아직 안 닫힌)인 마지막 인덱스여야 해요.
이 함수를 통해 호출되면 __close 메타메서드는 yield 할 수 없어요.
(이 함수는 릴리스 5.4.3에서 도입됐어요.)
lua_closethread
[-0, +?, –]
int lua_closethread (lua_State *L, lua_State *from);
스레드를 리셋해서 호출 스택을 정리하고 대기 중인 모든 to-be-closed 변수를 닫아요. 상태 코드를 리턴하는데, 스레드에 오류가 없으면(스레드를 멈춘 원래 오류나 닫는 메서드의 오류든) LUA_OK, 그렇지 않으면 오류 상태를 리턴해요. 오류가 있으면 오류 객체를 스택 꼭대기에 남겨둬요.
from 매개변수는 L을 리셋하는 코루틴을 나타내요. 그런 코루틴이 없으면 NULL이어도 돼요.
(이 함수는 릴리스 5.4.6에서 도입됐어요.)
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_OPEQ: 동등 비교(==)
-
LUA_OPLT: 미만 비교(<)
-
LUA_OPLE: 이하 비교(<=)
lua_concat
[-n, +1, e]
void lua_concat (lua_State *L, int n);
스택 꼭대기에 있는 n개의 값을 연결하고 pop 한 뒤 결과를 꼭대기에 남겨요. 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);
새 빈 테이블을 만들어 스택에 push 해요. 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 함수(lua_Writer 참고)를 호출해서 그 조각들을 써요.
strip이 참이면 공간을 아끼기 위해 바이너리 표현이 함수에 대한 모든 디버그 정보를 포함하지 않을 수 있어요.
리턴 값은 마지막 writer 호출이 리턴한 오류 코드예요. 0이면 오류가 없다는 뜻이에요.
이 함수는 스택에서 루아 함수를 pop 하지 않아요.
lua_error
[-1, +0, v]
int lua_error (lua_State *L);
스택 꼭대기의 값을 오류 객체로 사용해 루아 오류를 던져요. 이 함수는 long jump를 하므로 절대 리턴하지 않아요(luaL_error 참고).
lua_gc
[-0, +0, –]
int lua_gc (lua_State *L, int what, ...);
가비지 컬렉터를 제어해요.
이 함수는 what 매개변수의 값에 따라 여러 작업을 수행해요. 추가 인자가 필요한 옵션은 그 옵션 뒤에 인자를 나열해요.
-
LUA_GCCOLLECT: 전체 가비지 컬렉션 주기를 수행.
-
LUA_GCSTOP: 가비지 컬렉터를 멈춤.
-
LUA_GCRESTART: 가비지 컬렉터를 재시작.
-
LUA_GCCOUNT: 루아가 현재 사용하는 메모리 양(킬로바이트)을 리턴.
-
LUA_GCCOUNTB: 루아가 현재 사용하는 메모리의 바이트 수를 1024로 나눈 나머지를 리턴.
-
LUA_GCSTEP (int stepsize): stepsize 킬로바이트 할당에 해당하는 가비지 컬렉션의 증분 단계를 수행.
-
LUA_GCISRUNNING: 컬렉터가 실행 중인지(즉 멈추지 않았는지) 알려주는 불리언을 리턴.
-
LUA_GCINC (int pause, int stepmul, stepsize): 주어진 매개변수로 컬렉터를 증분 모드로 변경(§2.5.1). 이전 모드(LUA_GCGEN 또는 LUA_GCINC)를 리턴.
-
LUA_GCGEN (int minormul, int majormul): 주어진 매개변수로 컬렉터를 세대 모드로 변경(§2.5.2). 이전 모드(LUA_GCGEN 또는 LUA_GCINC)를 리턴.
이 옵션들에 대한 자세한 내용은 collectgarbage를 보세요.
이 함수는 파이널라이저가 호출하면 안 돼요.
lua_getallocf
[-0, +0, –]
lua_Alloc lua_getallocf (lua_State *L, void **ud);
주어진 상태의 메모리 할당 함수를 리턴해요. ud가 NULL이 아니면 루아는 메모리 할당자 함수를 설정할 때 주어진 불투명 포인터를 *ud에 저장해요.
lua_getfield
[-0, +1, e]
int lua_getfield (lua_State *L, int index, const char *k);
값 t[k]를 스택에 push 해요. 여기서 t는 주어진 인덱스의 값이에요. 루아에서처럼 이 함수는 "index" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
push 한 값의 타입을 리턴해요.
lua_getextraspace
[-0, +0, –]
void *lua_getextraspace (lua_State *L);
주어진 루아 상태와 연결된 원시 메모리 영역의 포인터를 리턴해요. 애플리케이션은 이 영역을 어떤 목적으로든 쓸 수 있어요. 루아는 여기에 아무것도 쓰지 않아요.
각 새 스레드는 이 영역이 메인 스레드 영역의 복사본으로 초기화돼요.
기본적으로 이 영역의 크기는 void 포인터 크기이지만, 루아를 다른 크기로 다시 컴파일할 수 있어요. (luaconf.h의 LUA_EXTRASPACE 보세요.)
lua_getglobal
[-0, +1, e]
int lua_getglobal (lua_State *L, const char *name);
전역 name의 값을 스택에 push 해요. 그 값의 타입을 리턴해요.
lua_geti
[-0, +1, e]
int lua_geti (lua_State *L, int index, lua_Integer i);
값 t[i]를 스택에 push 해요. 여기서 t는 주어진 인덱스의 값이에요. 루아에서처럼 이 함수는 "index" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
push 한 값의 타입을 리턴해요.
lua_getmetatable
[-0, +(0|1), –]
int lua_getmetatable (lua_State *L, int index);
주어진 인덱스의 값에 메타테이블이 있으면 그 메타테이블을 스택에 push 하고 1을 리턴해요. 그렇지 않으면 0을 리턴하고 스택에 아무것도 push 하지 않아요.
lua_gettable
[-1, +1, e]
int lua_gettable (lua_State *L, int index);
값 t[k]를 스택에 push 해요. 여기서 t는 주어진 인덱스의 값, k는 스택 꼭대기의 값이에요.
이 함수는 키를 스택에서 pop 하고 그 자리에 결과 값을 push 해요. 루아에서처럼 이 함수는 "index" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
push 한 값의 타입을 리턴해요.
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);
주어진 인덱스의 전체 유저데이터에 연결된 n번째 유저 값을 스택에 push 하고 push 한 값의 타입을 리턴해요.
유저데이터에 그 값이 없으면 nil을 push 하고 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.h의 LUA_INT_TYPE 보세요.)
루아는 이 타입에 들어가는 최솟값과 최댓값을 가진 상수 LUA_MININTEGER와 LUA_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);
주어진 인덱스의 값이 라이트 유저데이터이면 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);
주어진 인덱스의 값이 유저데이터(전체든 라이트든)이면 1, 아니면 0을 리턴해요.
lua_isyieldable
[-0, +0, –]
int lua_isyieldable (lua_State *L);
주어진 코루틴이 yield 할 수 있으면 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)와 동등하며 "길이" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4). 결과는 스택에 push 돼요.
lua_load
[-0, +1, –]
int lua_load (lua_State *L,
lua_Reader reader,
void *data,
const char *chunkname,
const char *mode);
루아 청크를 실행하지 않고 로드해요. 오류가 없으면 lua_load는 컴파일된 청크를 루아 함수로 스택 꼭대기에 push 해요. 그렇지 않으면 오류 메시지를 push 해요.
lua_load 함수는 사용자가 제공한 reader 함수(lua_Reader 참고)로 청크를 읽어요. data 인자는 reader 함수에 전달되는 불투명 값이에요.
chunkname 인자는 청크에 이름을 붙여주는데, 이 이름은 오류 메시지와 디버그 정보에 사용돼요(§4.7).
lua_load는 청크가 텍스트인지 바이너리인지 자동으로 감지해서 그에 맞게 로드해요(luac 프로그램 참고). mode 문자열은 load 함수에서처럼 동작하는데, 추가로 NULL 값이 문자열 "bt"와 동등해요.
lua_load는 내부적으로 스택을 사용하므로 reader 함수는 리턴할 때 항상 스택을 그대로 두어야 해요.
lua_load는 LUA_OK, LUA_ERRSYNTAX, LUA_ERRMEM을 리턴할 수 있어요. reader 함수가 던진 오류에 해당하는 다른 값도 리턴할 수 있어요(§4.4.1).
결과 함수에 업밸류가 있으면 그 첫 번째 업밸류는 레지스트리의 LUA_RIDX_GLOBALS 인덱스(§4.3)에 저장된 전역 환경의 값으로 설정돼요. 메인 청크를 로드할 때 이 업밸류는 _ENV 변수(§2.2)가 돼요. 다른 업밸류는 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);
새 빈 테이블을 만들어 스택에 push 해요. lua_createtable(L,0,0)과 동등해요.
lua_newthread
[-0, +1, m]
lua_State *lua_newthread (lua_State *L);
새 스레드를 만들어 스택에 push 하고, 이 새 스레드를 나타내는 lua_State의 포인터를 리턴해요. 이 함수가 리턴한 새 스레드는 원래 스레드와 전역 환경을 공유하지만 실행 스택은 독립적이에요.
스레드는 다른 루아 객체와 마찬가지로 가비지 컬렉션의 대상이에요.
lua_newuserdatauv
[-0, +1, m]
void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);
새 전체 유저데이터를 만들어 스택에 push 하는 함수예요. nuvalue개의 연관 루아 값(유저 값이라고 불러요)과 size바이트의 연관 원시 메모리 블록을 함께 만들어요. (유저 값은 lua_setiuservalue와 lua_getiuservalue 함수로 설정·읽을 수 있어요.)
함수는 메모리 블록의 주소를 리턴해요. 루아는 해당 유저데이터가 살아 있는 동안(§2.5) 이 주소가 유효함을 보장해요. 게다가 유저데이터가 파이널라이제이션으로 표시되면(§2.5.3) 그 주소는 파이널라이저 호출까지는 최소한 유효해요.
lua_next
[-1, +(2|0), v]
int lua_next (lua_State *L, int index);
스택에서 키를 pop 하고, 주어진 인덱스에 있는 테이블에서 그 키 다음에 오는 "다음" 키-값 쌍을 push 해요. 테이블에 더 이상 요소가 없으면 lua_next는 0을 리턴하고 아무것도 push 하지 않아요.
전형적인 테이블 순회는 다음과 같아요.
/* table is in the stack at index 't' */
lua_pushnil(L); /* first key */
while (lua_next(L, t) != 0) {
/* uses 'key' (at index -2) and 'value' (at index -1) */
printf("%s - %s\n",
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
/* removes 'value'; keeps 'key' for next iteration */
lua_pop(L, 1);
}
테이블을 순회하는 동안 키에 lua_tolstring을 직접 호출하지 않는 게 좋아요. 키가 실제로 문자열인 걸 알고 있지 않다면요. lua_tolstring은 주어진 인덱스의 값을 바꿀 수 있는데, 그러면 다음 lua_next 호출이 헷갈리거든요.
주어진 키가 nil이 아니고 테이블에 없으면 이 함수는 오류를 던질 수 있어요. 순회 중에 테이블을 수정할 때의 주의사항은 next 함수를 보세요.
lua_Number
typedef ... lua_Number;
루아에서 실수의 타입이에요.
기본적으로 이 타입은 double이지만, 단일 float이나 long double로 바꿀 수 있어요. (luaconf.h의 LUA_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);
함수(또는 호출 가능한 객체)를 보호 모드로 호출해요.
nargs와 nresults 둘 다 lua_call에서와 같은 의미예요. 호출 중 오류가 없으면 lua_pcall은 lua_call과 완전히 똑같이 동작해요. 하지만 오류가 있으면 lua_pcall은 그 오류를 잡아 스택에 값을 하나(오류 객체) push 하고 오류 코드를 리턴해요. 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);
호출된 함수가 yield 할 수 있다는 점만 빼면 lua_pcall과 완전히 똑같이 동작해요(§4.5).
lua_pop
[-n, +0, e]
void lua_pop (lua_State *L, int n);
스택에서 n개의 요소를 pop 해요. lua_settop 위에 만든 매크로로 구현돼요.
lua_pushboolean
[-0, +1, –]
void lua_pushboolean (lua_State *L, int b);
값이 b인 불리언 값을 스택에 push 해요.
lua_pushcclosure
[-n, +1, m]
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
새 C 클로저를 스택에 push 해요. 이 함수는 C 함수의 포인터를 받아, 호출되면 해당 C 함수를 호출하는 타입 function의 루아 값을 스택에 push 해요. n 매개변수는 이 함수가 가질 업밸류 개수예요(§4.2).
루아가 호출할 수 있는 함수라면 루아와 매개변수를 주고받는 정확한 프로토콜을 따라야 해요(lua_CFunction 참고).
C 함수를 만들 때 그 함수에 몇몇 값을 묶어줄 수 있는데, 이게 업밸류예요. 이 업밸류들은 함수가 호출될 때마다 접근할 수 있고요. 이렇게 묶는 걸 C 클로저(§4.2)라고 해요. C 클로저를 만들려면 먼저 업밸류의 초기 값들을 스택에 push 해요. (업밸류가 여러 개면 첫 번째 값을 먼저 push 해요.) 그다음 lua_pushcclosure를 호출해서 C 함수를 만들어 스택에 push 하는데, n 인자로 함수에 묶일 값의 개수를 알려줘요. lua_pushcclosure는 이 값들을 스택에서 pop 하기도 해요.
n의 최댓값은 255예요.
n이 0이면 이 함수는 라이트 C 함수(light C function)를 만들어요. 이는 C 함수의 포인터일 뿐이에요. 그 경우 메모리 오류를 절대 던지지 않아요.
lua_pushcfunction
[-0, +1, –]
void lua_pushcfunction (lua_State *L, lua_CFunction f);
C 함수를 스택에 push 해요. 업밸류가 없는 lua_pushcclosure와 동등해요.
lua_pushfstring
[-0, +1, v]
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
포맷된 문자열을 스택에 push 하고 이 문자열의 포인터를 리턴해요(§4.1.3). ISO C의 sprintf와 비슷하지만 중요한 차이가 두 가지 있어요. 첫째, 결과 공간을 할당할 필요가 없어요. 결과는 루아 문자열이고 루아가 메모리 할당(그리고 가비지 컬렉션을 통한 해제)을 관리해 주거든요. 둘째, 변환 지정자가 아주 제한적이에요. 플래그나 폭, 정밀도가 없어요. 변환 지정자는 '%%'(문자 '%' 삽입), '%s'(크기 제한 없는 0으로 끝나는 문자열 삽입), '%f'(lua_Number 삽입), '%I'(lua_Integer 삽입), '%p'(포인터 삽입), '%d'(int 삽입), '%c'(int를 1바이트 문자로 삽입), '%U'(long int를 UTF-8 바이트 시퀀스로 삽입)뿐이에요.
이 함수는 메모리 넘침이나 잘못된 변환 지정자 때문에 오류를 던질 수 있어요.
lua_pushglobaltable
[-0, +1, –]
void lua_pushglobaltable (lua_State *L);
전역 환경을 스택에 push 해요.
lua_pushinteger
[-0, +1, –]
void lua_pushinteger (lua_State *L, lua_Integer n);
값이 n인 정수를 스택에 push 해요.
lua_pushlightuserdata
[-0, +1, –]
void lua_pushlightuserdata (lua_State *L, void *p);
라이트 유저데이터를 스택에 push 해요.
유저데이터는 루아에서 C 값을 나타내요. 라이트 유저데이터는 포인터, void*를 나타내죠. 이는 값(숫자 같은)이에요. 만들지도 않고, 개별 메타테이블도 없고, 컬렉션 되지도 않아요(애초에 만들어진 적이 없으니까). 라이트 유저데이터는 같은 C 주소를 가진 '어떤' 라이트 유저데이터와도 동등해요.
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의 문자열을 스택에 push 해요. 루아는 주어진 문자열의 내부 사본을 만들거나 재사용하므로, 함수가 리턴한 직후 s의 메모리를 해제하거나 재사용해도 돼요. 문자열은 포함된 0바이트를 포함한 어떤 바이너리 데이터든 담을 수 있어요.
문자열의 내부 사본 포인터를 리턴해요(§4.1.3).
lua_pushnil
[-0, +1, –]
void lua_pushnil (lua_State *L);
nil 값을 스택에 push 해요.
lua_pushnumber
[-0, +1, –]
void lua_pushnumber (lua_State *L, lua_Number n);
값이 n인 실수를 스택에 push 해요.
lua_pushstring
[-0, +1, m]
const char *lua_pushstring (lua_State *L, const char *s);
s가 가리키는 0으로 끝나는 문자열을 스택에 push 해요. 루아는 주어진 문자열의 내부 사본을 만들거나 재사용하므로, 함수가 리턴한 직후 s의 메모리를 해제하거나 재사용해도 돼요.
문자열의 내부 사본 포인터를 리턴해요(§4.1.3).
s가 NULL이면 nil을 push 하고 NULL을 리턴해요.
lua_pushthread
[-0, +1, –]
int lua_pushthread (lua_State *L);
L이 나타내는 스레드를 스택에 push 해요. 이 스레드가 자기 상태의 메인 스레드이면 1을 리턴해요.
lua_pushvalue
[-0, +1, –]
void lua_pushvalue (lua_State *L, int index);
주어진 인덱스에 있는 요소의 복사본을 스택에 push 해요.
lua_pushvfstring
[-0, +1, v]
const char *lua_pushvfstring (lua_State *L,
const char *fmt,
va_list argp);
가변 인자 대신 va_list를 받는다는 점만 빼면 lua_pushfstring과 동등해요.
lua_rawequal
[-0, +0, –]
int lua_rawequal (lua_State *L, int index1, int index2);
인덱스 index1과 index2의 두 값이 원시적으로 동등하면(즉 __eq 메타메서드를 호출하지 않고 동등하면) 1을 리턴해요. 그렇지 않으면 0을 리턴해요. 인덱스가 유효하지 않아도 0을 리턴하고요.
lua_rawget
[-1, +1, –]
int lua_rawget (lua_State *L, int index);
lua_gettable과 비슷하지만 원시 접근(메타메서드 없이)을 해요. index의 값은 테이블이어야 해요.
lua_rawgeti
[-0, +1, –]
int lua_rawgeti (lua_State *L, int index, lua_Integer n);
값 t[n]을 스택에 push 해요. 여기서 t는 주어진 인덱스의 테이블이에요. 접근은 원시적이어서 __index 메타 값을 사용하지 않아요.
push 한 값의 타입을 리턴해요.
lua_rawgetp
[-0, +1, –]
int lua_rawgetp (lua_State *L, int index, const void *p);
값 t[k]를 스택에 push 해요. 여기서 t는 주어진 인덱스의 테이블이고 k는 라이트 유저데이터로 표현된 포인터 p예요. 접근은 원시적이어서 __index 메타 값을 사용하지 않아요.
push 한 값의 타입을 리턴해요.
lua_rawlen
[-0, +0, –]
lua_Unsigned lua_rawlen (lua_State *L, int index);
주어진 인덱스의 값의 원시 "길이"를 리턴해요. 문자열이면 문자열 길이, 테이블이면 메타메서드 없는 길이 연산자('#')의 결과, 유저데이터면 그 유저데이터용으로 할당된 메모리 블록의 크기예요. 다른 값이면 0을 리턴해요.
lua_rawset
[-2, +0, m]
void lua_rawset (lua_State *L, int index);
lua_settable과 비슷하지만 원시 할당(메타메서드 없이)을 해요. index의 값은 테이블이어야 해요.
lua_rawseti
[-1, +0, m]
void lua_rawseti (lua_State *L, int index, lua_Integer i);
t[i] = v와 동등한 일을 해요. 여기서 t는 주어진 인덱스의 테이블, v는 스택 꼭대기의 값이에요.
이 함수는 스택에서 값을 pop 해요. 할당은 원시적이어서 __newindex 메타 값을 사용하지 않아요.
lua_rawsetp
[-1, +0, m]
void lua_rawsetp (lua_State *L, int index, const void *p);
t[p] = v와 동등한 일을 해요. 여기서 t는 주어진 인덱스의 테이블, p는 라이트 유저데이터로 인코딩되고, v는 스택 꼭대기의 값이에요.
이 함수는 스택에서 값을 pop 해요. 할당은 원시적이어서 __newindex 메타 값을 사용하지 않아요.
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
void *data,
size_t *size);
lua_load가 사용하는 reader 함수예요. lua_load가 청크의 다른 조각이 필요할 때마다 자기 data 매개변수와 함께 reader를 호출해요. reader는 청크의 새 조각이 담긴 메모리 블록 포인터를 리턴하고 블록 크기를 size에 설정해야 해요. 블록은 reader 함수가 다시 호출될 때까지 존재해야 해요. 청크의 끝을 알리려면 reader는 NULL을 리턴하거나 size를 0으로 설정해야 해요. reader 함수는 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);
꼭대기 요소를 주어진 유효 인덱스로 옮기는데 요소를 밀지 않아요(그래서 그 인덱스의 값을 대체해요). 그다음 꼭대기 요소를 pop 해요.
lua_resetthread
[-0, +?, –]
int lua_resetthread (lua_State *L);
이 함수는 deprecated(사용 중단)됐어요. from이 NULL인 lua_closethread와 동등해요.
lua_resume
[-?, +?, –]
int lua_resume (lua_State *L, lua_State *from, int nargs,
int *nresults);
주어진 스레드 L에서 코루틴을 시작하고 재개해요.
코루틴을 시작하려면 스레드의 빈 스택에 메인 함수와 인자들을 push 하고 lua_resume을 호출하면 돼요. nargs는 인자 개수예요. 이 호출은 코루틴이 중단되거나 실행을 끝낼 때 리턴해요. 리턴할 때 *nresults가 갱신되고, 스택 꼭대기에는 lua_yield에 넘겨진 값이나 본문 함수가 리턴한 값인 *nresults개의 값이 들어 있어요. lua_resume은 코루틴이 yield 하면 LUA_YIELD, 오류 없이 실행을 끝내면 LUA_OK, 오류가 있으면 오류 코드를 리턴해요(§4.4.1). 오류가 있으면 오류 객체가 스택 꼭대기에 있어요.
코루틴을 재개하려면 스택에서 yield 된 *nresults개의 값을 제거하고, yield의 결과로 전달할 값들을 push 한 다음 lua_resume을 호출해요.
from 매개변수는 L을 재개하는 코루틴을 나타내요. 그런 코루틴이 없으면 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);
주어진 상태의 할당자 함수를 사용자 데이터 ud와 함께 f로 변경해요.
lua_setfield
[-1, +0, e]
void lua_setfield (lua_State *L, int index, const char *k);
t[k] = v와 동등한 일을 해요. 여기서 t는 주어진 인덱스의 값, v는 스택 꼭대기의 값이에요.
이 함수는 스택에서 값을 pop 해요. 루아에서처럼 이 함수는 "newindex" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
lua_setglobal
[-1, +0, e]
void lua_setglobal (lua_State *L, const char *name);
스택에서 값을 pop 해서 전역 name의 새 값으로 설정해요.
lua_seti
[-1, +0, e]
void lua_seti (lua_State *L, int index, lua_Integer n);
t[n] = v와 동등한 일을 해요. 여기서 t는 주어진 인덱스의 값, v는 스택 꼭대기의 값이에요.
이 함수는 스택에서 값을 pop 해요. 루아에서처럼 이 함수는 "newindex" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
lua_setiuservalue
[-1, +0, –]
int lua_setiuservalue (lua_State *L, int index, int n);
스택에서 값을 pop 해서 주어진 인덱스의 전체 유저데이터에 연결된 새 n번째 유저 값으로 설정해요. 유저데이터에 그 값이 없으면 0을 리턴해요.
lua_setmetatable
[-1, +0, –]
int lua_setmetatable (lua_State *L, int index);
스택에서 테이블이나 nil을 pop 해서 그 값을 주어진 인덱스의 값의 새 메타테이블로 설정해요. (nil은 메타테이블이 없음을 뜻해요.)
(역사적 이유로 이 함수는 int를 리턴하는데, 지금은 항상 1이에요.)
lua_settable
[-2, +0, e]
void lua_settable (lua_State *L, int index);
t[k] = v와 동등한 일을 해요. 여기서 t는 주어진 인덱스의 값, v는 스택 꼭대기 값, k는 그 바로 아래 값이에요.
이 함수는 키와 값을 모두 스택에서 pop 해요. 루아에서처럼 이 함수는 "newindex" 이벤트에 대한 메타메서드를 호출할 수 있어요(§2.4).
lua_settop
[-?, +?, e]
void lua_settop (lua_State *L, int index);
어떤 인덱스든, 또는 0을 받아서 스택 꼭대기를 그 인덱스로 설정해요. 새 꼭대기가 이전보다 크면 새 요소들은 nil로 채워져요. index가 0이면 모든 스택 요소가 제거돼요.
이 함수는 to-be-closed로 표시된 인덱스를 스택에서 제거할 때 임의의 코드를 실행할 수 있어요.
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_OK인 스레드(새 코루틴 시작)나 LUA_YIELD인 스레드(코루틴 재개)는 재개할 수 있어요.
lua_stringtonumber
[-0, +1, –]
size_t lua_stringtonumber (lua_State *L, const char *s);
0으로 끝나는 문자열 s를 숫자로 변환하고 그 숫자를 스택에 push 하며, 문자열의 전체 크기(즉 길이 + 1)를 리턴해요. 변환은 루아의 어휘 규칙(§3.1)에 따라 정수나 실수가 될 수 있어요. 문자열은 앞뒤 공백과 부호를 가질 수 있어요. 문자열이 유효한 숫자가 아니면 0을 리턴하고 아무것도 push 하지 않아요. (결과를 불리언으로 쓸 수 있는데, 변환 성공 시 참이에요.)
lua_toboolean
[-0, +0, –]
int lua_toboolean (lua_State *L, int index);
주어진 인덱스의 루아 값을 C 불리언 값(0 또는 1)으로 변환해요. 루아의 모든 테스트처럼 lua_toboolean은 false와 nil이 아닌 어떤 루아 값에 대해서도 참을 리턴하고, 그 외에는 거짓을 리턴해요. (실제 불리언 값만 받고 싶다면 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);
스택의 주어진 인덱스를 to-be-closed 슬롯으로 표시해요(§3.3.8). 루아의 to-be-closed 변수처럼, 그 슬롯의 값은 범위를 벗어날 때 닫혀요. C 함수 맥락에서 범위를 벗어난다는 것은, 실행 중인 함수가 루아로 리턴하거나, 오류가 나거나, 그 슬롯이 lua_settop이나 lua_pop으로 스택에서 제거되거나, lua_closeslot 호출이 일어나는 것을 뜻해요. to-be-closed로 표시된 슬롯은 lua_closeslot으로 미리 비활성화하지 않는 한, lua_settop이나 lua_pop을 제외한 API의 다른 어떤 함수로도 스택에서 제거하면 안 돼요.
주어진 슬롯의 값이 __close 메타메서드를 갖지도 않고 false 값도 아니면 이 함수는 오류를 던져요.
활성 to-be-closed 슬롯과 같거나 그보다 아래인 인덱스에 대해 이 함수를 호출하면 안 돼요.
오류의 경우든 정상 리턴의 경우든, __close 메타메서드가 실행될 즈음에는 C 스택이 이미 풀려 있어서 호출 함수에 선언된 어떤 자동 C 변수(예: 버퍼)도 범위를 벗어난 상태라는 점을 참고하세요.
lua_tointeger
[-0, +0, –]
lua_Integer lua_tointeger (lua_State *L, int index);
isnum이 NULL인 lua_tointegerx와 동등해요.
lua_tointegerx
[-0, +0, –]
lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
주어진 인덱스의 루아 값을 부호 있는 정수 타입 lua_Integer로 변환해요. 루아 값은 정수이거나 정수로 변환 가능한 숫자·문자열(§3.4.3)이어야 해요. 그렇지 않으면 lua_tointegerx는 0을 리턴해요.
isnum이 NULL이 아니면 그 피참조자에 연산이 성공했는지 알려주는 불리언 값을 할당해요.
lua_tolstring
[-0, +0, m]
const char *lua_tolstring (lua_State *L, int index, size_t *len);
주어진 인덱스의 루아 값을 C 문자열로 변환해요. len이 NULL이 아니면 *len에 문자열 길이를 설정해요. 루아 값은 문자열이거나 숫자여야 해요. 그렇지 않으면 함수는 NULL을 리턴해요. 값이 숫자면 lua_tolstring은 스택에 있는 실제 값을 문자열로 바꾸기도 해요. (이 변경은 테이블 순회 중에 키에 lua_tolstring을 적용할 때 lua_next를 헷갈리게 해요.)
lua_tolstring은 루아 상태 안의 문자열 포인터를 리턴해요(§4.1.3). 이 문자열은 항상 마지막 문자 뒤에 0('\0')을 가지며(C에서처럼) 본문에는 다른 0을 포함할 수 있어요.
이 함수는 숫자를 문자열로 변환할 때(그러면 새 문자열을 만들 수 있으니)에만 메모리 오류를 던질 수 있어요.
lua_tonumber
[-0, +0, –]
lua_Number lua_tonumber (lua_State *L, int index);
isnum이 NULL인 lua_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을 리턴해요.
isnum이 NULL이 아니면 그 피참조자에 연산이 성공했는지 알려주는 불리언 값을 할당해요.
lua_topointer
[-0, +0, –]
const void *lua_topointer (lua_State *L, int index);
주어진 인덱스의 값을 일반적인 C 포인터(void*)로 변환해요. 값은 유저데이터, 테이블, 스레드, 문자열, 함수일 수 있어요. 그렇지 않으면 lua_topointer는 NULL을 리턴해요. 서로 다른 객체는 서로 다른 포인터를 줘요. 포인터를 다시 원래 값으로 되돌릴 방법은 없어요.
보통 이 함수는 해싱과 디버그 정보에만 사용해요.
lua_tostring
[-0, +0, m]
const char *lua_tostring (lua_State *L, int index);
len이 NULL인 lua_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);
주어진 인덱스의 값이 전체 유저데이터면 그 메모리 블록 주소를 리턴해요. 값이 라이트 유저데이터면 그 값(포인터)을 리턴해요. 그렇지 않으면 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);
값 tp로 부호화된 타입의 이름을 리턴해요. tp는 lua_type이 리턴하는 값 중 하나여야 해요.
lua_Unsigned
typedef ... lua_Unsigned;
lua_Integer의 부호 없는 버전이에요.
lua_upvalueindex
[-0, +0, –]
int lua_upvalueindex (int i);
실행 중인 함수의 i번째 업밸류를 나타내는 의사 인덱스를 리턴해요(§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가 사용하는 writer 함수의 타입이에요.
lua_dump가 청크의 조각을 하나 만들 때마다 writer를 호출해서 쓸 버퍼(p), 그 크기(sz), lua_dump에 제공된 ud 매개변수를 넘겨줘요.
writer는 오류 코드를 리턴해요. 0은 오류 없음, 다른 값은 오류를 뜻하며 lua_dump가 writer를 다시 호출하지 않게 해요.
lua_xmove
[-?, +?, –]
void lua_xmove (lua_State *from, lua_State *to, int n);
같은 상태의 서로 다른 스레드 간에 값을 교환해요.
이 함수는 from 스택에서 n개의 값을 pop 해서 to 스택에 push 해요.
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);
코루틴(스레드)을 yield 해요.
C 함수가 lua_yieldk를 호출하면 실행 중인 코루틴이 실행을 중단하고, 이 코루틴을 시작한 lua_resume 호출이 리턴해요. nresults 매개변수는 결과로 lua_resume에 전달될 스택의 값 개수예요.
코루틴이 다시 재개되면 루아는 주어진 연속 함수 k를 호출해서 yield 했던 C 함수의 실행을 이어가요(§4.5). 이 연속 함수는 이전 함수와 같은 스택을 받는데, n개의 결과가 제거되고 lua_resume에 전달된 인자들로 대체돼 있어요. 게다가 연속 함수는 lua_yieldk에 전달된 값 ctx도 받아요.
보통 이 함수는 리턴하지 않아요. 코루틴이 결국 재개되면 연속 함수의 실행을 이어가거든요. 하지만 특별한 경우가 하나 있어요. 이 함수가 라인 훅이나 카운트 훅 안에서 호출되는 경우예요(§4.7). 그 경우 lua_yieldk는 연속 함수 없이(아마 lua_yield 형태로) 결과 없이 호출되어야 하고, 훅은 그 호출 직후 즉시 리턴해야 해요. 루아가 yield 하고, 코루틴이 다시 재개되면 훅을 촉발한 (루아) 함수의 정상 실행을 이어갈 거예요.
이 함수는 연속 함수가 없는 대기 중인 C 호출이 있는 스레드(소위 C-call boundary)에서 호출되거나, resume 안에서 실행되지 않는 스레드(보통 메인 스레드)에서 호출되면 오류를 던질 수 있어요.
4.7 — The Debug Interface (디버그 인터페이스)
루아에는 내장 디버깅 기능이 없어요. 대신 함수들과 훅(hook)을 통한 특별한 인터페이스를 제공해요. 이 인터페이스 덕분에 인터프리터의 '내부 정보'가 필요한 여러 가지 디버거, 프로파일러, 기타 도구들을 만들 수 있어요.
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) number of upvalues */
unsigned char nparams; /* (u) number of parameters */
char isvararg; /* (u) */
char istailcall; /* (t) */
unsigned short ftransfer; /* (r) index of first value transferred */
unsigned short ntransfer; /* (r) number of transferred values */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
<em>other fields</em>
} lua_Debug;
함수나 활성 레코드에 대한 여러 정보를 담는 데 쓰는 구조체예요. lua_getstack은 나중에 쓰려고 이 구조체의 private 부분만 채워요. lua_Debug의 다른 필드를 유용한 정보로 채우려면 적절한 매개변수로 lua_getinfo를 호출해야 해요. (특히 필드를 얻으려면 필드 주석에서 괄호 안의 문자를 lua_getinfo의 what 매개변수에 추가해야 해요.)
lua_Debug의 필드는 다음과 같은 의미를 가져요.
-
source: 함수를 만든 청크의 소스. source가 '@'로 시작하면 함수가 파일에서 정의됐고 그 파일 이름이 '@' 뒤에 온다는 뜻이에요. source가 '='로 시작하면 나머지 내용이 사용자 의존적인 방식으로 소스를 설명해요. 그 외에는 함수가 문자열에서 정의됐고 source가 그 문자열이에요.
-
srclen: 문자열 source의 길이.
-
short_src: 오류 메시지에 쓰는 source의 "인쇄 가능한" 버전.
-
linedefined: 함수 정의가 시작되는 줄 번호.
-
lastlinedefined: 함수 정의가 끝나는 줄 번호.
-
what: 함수가 루아 함수면 "Lua", C 함수면 "C", 청크의 메인 부분이면 "main"이라는 문자열.
-
currentline: 주어진 함수가 실행 중인 현재 줄. 줄 정보를 쓸 수 없으면 currentline은 -1로 설정돼요.
-
name: 주어진 함수에 대한 합리적인 이름. 루아에서 함수는 일급 값이라 고정 이름이 없어요. 어떤 함수는 여러 전역 변수의 값일 수 있고, 어떤 함수는 테이블 필드에만 저장될 수도 있거든요. lua_getinfo 함수는 함수가 어떻게 호출됐는지 확인해서 적절한 이름을 찾아요. 이름을 찾지 못하면 name은 NULL로 설정돼요.
-
namewhat: name 필드를 설명해요. namewhat의 값은 함수가 어떻게 호출됐는지에 따라 "global", "local", "method", "field", "upvalue", 또는 ""(빈 문자열)일 수 있어요. (루아는 다른 선택지가 어울리지 않을 때 빈 문자열을 써요.)
-
istailcall: 이 함수 호출이 꼬리 호출로 호출됐다면 참. 이 경우 이 레벨의 호출자는 스택에 없어요.
-
nups: 함수의 업밸류 개수.
-
nparams: 함수의 매개변수 개수(C 함수에서는 항상 0).
-
isvararg: 함수가 가변 인자 함수라면 참(C 함수에서는 항상 참).
-
ftransfer: "전송"되는 첫 번째 값의 스택 인덱스. 즉 호출의 매개변수나 리턴의 리턴 값이에요. (다른 값들은 연속된 인덱스에 있어요.) 이 인덱스로 lua_getlocal과 lua_setlocal을 통해 이 값들에 접근하고 수정할 수 있어요. 이 필드는 call 훅(첫 매개변수를 뜻함)이나 return 훅(리턴되는 첫 값을 뜻함) 동안에만 의미 있어요. (call 훅에서는 이 값이 항상 1이에요.)
-
ntransfer: 전송되는 값의 개수(앞 항목 참고). (루아 함수의 호출에서는 이 값이 항상 nparams와 같아요.)
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 참고)의 인자로 주어진 유효한 활성 레코드여야 해요.
함수에 대한 정보를 얻으려면 함수를 스택에 push 하고 what 문자열을 문자 '>'로 시작해요. (그 경우 lua_getinfo는 스택 꼭대기에서 함수를 pop 해요.) 예를 들어 함수 f가 어느 줄에서 정의됐는지 알려면 다음 코드를 쓸 수 있어요.
lua_Debug ar;
lua_getglobal(L, "f"); /* get global 'f' */
lua_getinfo(L, ">S", &ar);
printf("%d\n", ar.linedefined);
what 문자열의 각 문자는 구조체 ar의 어떤 필드를 채울지, 또는 스택에 push 할 값을 고르게 해요. (이 문자들은 lua_Debug 구조체 선언의 각 필드 뒤 주석 괄호 안에도 문서화되어 있어요.)
-
'f': 주어진 레벨에서 실행되는 함수를 스택에 push.
-
'l': currentline 필드를 채움.
-
'n': name과 namewhat 필드를 채움.
-
'r': ftransfer와 ntransfer 필드를 채움.
-
'S': source, short_src, linedefined, lastlinedefined, what 필드를 채움.
-
't': istailcall 필드를 채움.
-
'u': nups, nparams, isvararg 필드를 채움.
-
'L': 인덱스가 함수에서 코드가 연결된 줄들(즉 중단점을 놓을 수 있는 줄들)인 테이블을 스택에 push. (코드가 없는 줄에는 빈 줄과 주석이 포함돼요.) 이 옵션을 'f' 옵션과 함께 주면 그 테이블이 함수 다음에 push 돼요. 이 옵션만 메모리 오류를 던질 수 있어요.
이 함수는 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은 변수의 값을 스택에 push 하고 그 이름을 리턴해요.
두 번째 경우, ar은 NULL이어야 하고 살펴볼 함수가 스택 꼭대기에 있어야 해요. 이 경우 루아 함수의 매개변수만 보여요(어떤 변수가 활성인지에 대한 정보가 없으니까) 그리고 스택에는 아무것도 push 되지 않아요.
인덱스가 활성 지역 변수 개수보다 크면 NULL을 리턴하고(아무것도 push 하지 않고)요.
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번째 업밸류에 대한 정보를 얻어요. 업밸류의 값을 스택에 push 하고 그 이름을 리턴해요. 인덱스 n이 업밸류 개수보다 크면 NULL을 리턴하고(아무것도 push 하지 않고)요.
업밸류에 대한 자세한 내용은 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를 호출해야 해요.
call 이벤트에서 event는 정상 값인 LUA_HOOKCALL일 수도, 꼬리 호출을 위한 LUA_HOOKTAILCALL일 수도 있어요. 이 경우 대응하는 return 이벤트는 없어요.
루아는 훅을 실행하는 동안 다른 훅 호출을 비활성화해요. 그래서 훅이 루아를 다시 호출해서 함수나 청크를 실행하면, 그 실행은 훅 호출 없이 일어나요.
훅 함수는 연속 함수를 가질 수 없어요. 즉 널이 아닌 k로 lua_yieldk, lua_pcallk, lua_callk를 호출할 수 없어요.
훅 함수는 다음 조건에서 yield 할 수 있어요. count 이벤트와 line 이벤트만 yield 할 수 있고, yield 하려면 훅 함수는 nresults가 0(즉 값 없음)인 lua_yield를 호출하면서 실행을 끝내야 해요.
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가 포함될 때만 의미 있어요. 각 이벤트에서 훅은 아래 설명대로 호출돼요.
-
call 훅: 인터프리터가 함수를 호출할 때 호출돼요. 훅은 루아가 새 함수에 들어간 직후 호출돼요.
-
return 훅: 인터프리터가 함수에서 리턴할 때 호출돼요. 훅은 루아가 함수를 떠나기 직전에 호출돼요.
-
line 훅: 인터프리터가 새 코드 줄의 실행을 시작하려 할 때, 또는 코드에서 뒤로 점프할 때(같은 줄이라도) 호출돼요. 이 이벤트는 루아가 루아 함수를 실행하는 동안에만 일어나요.
-
count 훅: 인터프리터가 매 count개의 명령을 실행한 뒤 호출돼요. 이 이벤트는 루아가 루아 함수를 실행하는 동안에만 일어나요.
훅은 mask를 0으로 설정하면 비활성화돼요.
lua_setlocal
[-(0|1), +0, –]
const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
주어진 활성 레코드의 지역 변수의 값을 설정해요. 스택 꼭대기의 값을 그 변수에 할당하고 그 이름을 리턴해요. 스택에서 값도 pop 해요.
인덱스가 활성 지역 변수 개수보다 크면 NULL을 리턴하고(아무것도 pop 하지 않고)요.
ar과 n 매개변수는 lua_getlocal 함수에서와 같아요.
lua_setupvalue
[-(0|1), +0, –]
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
클로저의 업밸류 값을 설정해요. 스택 꼭대기의 값을 그 업밸류에 할당하고 그 이름을 리턴해요. 스택에서 값도 pop 해요.
인덱스 n이 업밸류 개수보다 크면 NULL을 리턴하고(아무것도 pop 하지 않고)요.
funcindex와 n 매개변수는 lua_getupvalue 함수에서와 같아요.
lua_upvalueid
[-0, +0, –]
void *lua_upvalueid (lua_State *L, int funcindex, int n);
인덱스 funcindex의 클로저에서 번호가 n인 업밸류의 고유 식별자를 리턴해요.
이 고유 식별자들로 프로그램은 서로 다른 클로저가 업밸류를 공유하는지 확인할 수 있어요. 업밸류를 공유하는(즉 같은 외부 지역 변수에 접근하는) 루아 클로저는 그 업밸류 인덱스에 대해 동일한 id를 리턴해요.
funcindex와 n 매개변수는 lua_getupvalue 함수에서와 같지만, n은 업밸류 개수보다 클 수 없어요.
lua_upvaluejoin
[-0, +0, –]
void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
int funcindex2, int n2);
인덱스 funcindex1의 루아 클로저의 n1번째 업밸류가 인덱스 funcindex2의 루아 클로저의 n2번째 업밸류를 가리키게 해요.
더 알아보기
책을 마치기 전에, 여기서 다룬 개념이 실제 루아 세계에서 어떻게 이어지는지 짚어볼게요.
-
모든 함수의 시그니처가 필요할 때: 이 문서 §4.6과 §4.7의
lua_*함수들을lua.h헤더와 함께 보면 바로 C 코드를 쓸 수 있어요. -
C에서 루아를 호출하는 실용적인 헬퍼들: 보조 라이브러리(Auxiliary Library)의
luaL_*함수들을 함께 쓰면 스택을 일일이 제어하지 않아도 훨씬 편하게 루아와 대화할 수 있어요. (예:luaL_newstate,luaL_dostring,luaL_checknumber등) 이 문서의 자연스러운 다음 장이죠. -
함수의 표기법: 각 함수마다 붙어 있는
[-o, +p, *x*]표기는 스택에서 pop/push 하는 개수와 오류 가능성을 한 줄로 요약한 거예요. 코드를 읽을 때 이 표기부터 보면 함수가 스택을 어떻게 쓰는지 금방 감이 와요. -
동일한 원리를 루아 안에서 보려면: C API의 스택·레지스트리 개념은 루아의
load,pcall,debug라이브러리와도 이어져 있어요. C 쪽을 먼저 익히면 루아 내부 동작을 이해하는 데도 큰 도움이 돼요.
원문 전문과 최신 수정사항은 Lua 5.4 Reference Manual에서 확인할 수 있어요. 이 자료는 공식 매뉴얼의 비공식 번역본입니다.