저자: Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
번역: wariua
Copyright © 2015–2020 Lua.org, PUC-Rio. 루아 라이선스 하에서 자유롭게 사용 가능.
루아(Lua)는 강력하고 효율적이며 가벼운 내장형 스크립트 언어다. 절차적 프로그래밍, 객체 지향 프로그래밍, 함수형 프로그래밍, 데이터 주도 프로그래밍, 그리고 데이터 기술(description)을 지원한다.
루아에서는 단순한 절차적 문법이 연관 배열 및 확장식 의미론을 기반으로 한 데이터 기술 요소와 결합된다. 루아는 동적 타입 방식이고, 레지스터 기반 가상 머신으로 바이트코드를 해석해서 실행하며, 점진식 쓰레기 수집으로 메모리를 자동 관리한다. 그래서 설정, 스크립트, 빠른 프로토타입 만들기에 이상적이다.
루아는 라이브러리로 구현되어 있으며, 표준 C와 C++의
공통 부분집합인 순수 C로 작성되어 있다.
루아 배포판에는 lua
라는 호스트 프로그램이
포함되어 있는데, 루아 라이브러리를 이용해
완전한 단독형 루아 인터프리터를 제공한다.
이를 대화식 사용이나 배치 처리에 쓸 수 있다.
루아는 강력하고 가벼운 내장형 스크립트 언어로도,
또 강력하면서 가볍고 효율적인 단독 언어로도
쓸 수 있게 만들어졌다.
확장형 언어이기에 루아에는 "main" 프로그램 개념이 없다.
감싸는 프로그램 내지 호스트라 부르는
호스트 클라이언트에 내장되어 동작한다.
(많은 경우 이 호스트는 단독형 lua
프로그램이다.)
호스트 프로그램에서는 함수를 호출해서 루아 코드 조각을 실행할 수 있고,
루아 변수를 읽고 쓸 수 있으며,
루아 코드에서 호출할 C 함수를 등록할 수 있다.
C 함수 사용을 통해 광범위한 분야에 대처할 수 있도록
루아를 보강할 수 있으며, 그래서 문법적 틀을 공유하는
맞춤형 프로그래밍 언어를 만들 수 있다.
루아는 자유 소프트웨어이며
라이선스에서 선언하는 것처럼
늘 그렇듯 어떤 보증도 없이 제공된다.
이 매뉴얼에서 다루는 구현체를
루아의 공식 웹 사이트인 www.lua.org
에서 얻을 수 있다.
여느 참조 매뉴얼과 마찬가지로 이 문서는 많은 부분에서 건조하다. 루아 설계에 숨어 있는 결정들에 대한 논의는 루아 웹 사이트에 있는 기술 논문들을 보라. 루아 프로그래밍에 대한 자세한 소개는 Roberto의 책 Programming in Lua를 보라. (번역서: 프로그래밍 루아)
이 절에선 언어의 기본 개념들을 설명한다.
루아는 동적 타입 언어다. 즉, 변수에는 타입이 없고 값에만 타입이 있다. 언어 내에 타입 정의라는 것이 없다. 모든 값들이 각자의 타입을 가지고 있다.
루아에서 모든 값들은 일급(first-class) 값이다. 즉, 모든 값들을 변수에 저장하고, 다른 함수에 인자로 전달하고, 결과로 반환할 수 있다.
루아에는 여덟 가지 기본 타입이 있다.
닐(nil), 불리언, 수,
문자열, 함수, userdata,
스레드, 테이블이다.
닐 타입에는 값이 nil 하나만 있는데,
그 값의 주된 특징은 다른 어떤 값과도 다르다는 점이다.
일반적으로 이 값으로 유용한 값이 없음을 나타낸다.
불리언 타입에는 false와 true라는
두 값이 있다.
nil과 false는 조건을 거짓으로 만든다.
그 외 다른 값들은 참으로 만든다.
수 타입은 정수와 실수(부동소수점수)
모두를 나타낸다.
문자열 타입은 불변 바이트 열을 나타낸다.
루아는 8비트 처리가 깔끔하다.
즉, 문자열에 어떤 8비트 값도 담을 수 있으며
0('\0
')을 포함시킬 수도 있다.
루아는 또한 인코딩에 불가지론적이다.
즉, 문자열 내용물에 대해 어떤 가정도 하지 않는다.
수 타입에는 두 가지 내부 표현,
즉 두 가지 서브타입이 있는데,
하나는 정수이고 다른 하나는 실수다.
루아에는 각 표현이 언제 쓰이는가에 대한 명확한 규칙이 있지만
필요에 따라 둘 사이에 자동으로 변환을 하기도 한다. (3.4.3절 참고.)
따라서 프로그래머가
정수와 실수 간의 차이를 대강 무시하기로 할 수도 있고
각 수의 표현을 완전히 통제하기로 할 수도 있다.
표준 루아에서는 64비트 정수와 배정밀도(64비트) 부동소수점수를 쓴다.
하지만 32비트 정수 및/또는 단정밀도(32비트) 부동소수점수를 쓰도록
루아를 컴파일할 수도 있다.
정수와 실수 모두에 32비트를 쓰는 방식은
특히 작은 머신과 임베디드 시스템에서 매력적이다.
(luaconf.h
파일의 LUA_32BITS
매크로 참고.)
루아에서는 루아로 작성된 함수와 C로 작성된 함수를 호출(및 조작)할 수 있다. (3.4.10절 참고.) 둘 모두 함수 타입으로 나타낸다.
userdata 타입은 임의의 C 데이터를 루아 변수에 저장할 수 있도록 하기 위한 것이다. userdata 값은 날것 그대로의 메모리 블록을 나타낸다. userdata에는 두 종류가 있는데, full userdata는 루아에서 관리하는 메모리 블럭을 가진 객체이고, light userdata는 그냥 C 포인터 값이다. 루아에서 userdata에는 할당과 동일성 검사를 제외하고 어떤 연산도 미리 정의되어 있지 않다. 메타테이블을 사용하면 프로그래머가 full userdata 값에 대한 연산을 정의할 수 있다. (2.4절 참고.) 루아 내에서는 userdata 값을 생성하거나 변경할 수 없으며 C API를 통해서만 가능하다. 이는 호스트 프로그램이 소유한 데이터의 무결성을 보장하기 위해서다.
스레드 타입은 독립적인 실행 스레드를 나타내며 코루틴을 구현하는 데 쓴다. (2.6절 참고.) 루아 스레드는 운영 체제 스레드와는 무관하다. 루아는 자체 스레드를 지원하지 않는 경우를 포함한 모든 시스템에서 코루틴을 지원한다.
테이블 타입은 연관 배열을 구현한 것이다.
즉, 인덱스로 정수만이 아니라 nil과 NaN을 제외한
모든 루아 값을 사용할 수 있는 배열이다.
(NaN(Not a Number)는 0/0
처럼
정의되어 있지 않거나 표현 불가능한 수치 결과를 나타내는 데
쓰는 특수한 값이다.)
테이블이 혼성일 수 있다.
즉, (nil을 빼고) 모든 타입의 값을 담을 수 있다.
값이 nil인 키는 테이블에 포함되는 것으로 보지 않는다.
달리 말해, 테이블에 포함되어 있지 않은 키에는 모두
nil 값이 연계되어 있는 것이다.
테이블은 루아에서 유일한 데이터 구조화 장치다.
테이블을 이용해 평범한 배열이나 리스트, 심볼 테이블,
집합, 레코드, 그래프, 트리 등을 표현할 수 있다.
루아에서 레코드를 표현할 때는 필드 이름을 인덱스로 사용한다.
언어에서 a["name"]
와 더불어 문법적 양념
a.name
을 통해서 그 표현을 지원한다.
루아에는 테이블을 만들 수 있는 여러 편리한 방법이 있다.
(3.4.9절 참고.)
인덱스와 마찬가지로 테이블 필드 값으로 어떤 타입이든 가능하다. 특히 함수가 일급 값이기 때문에 함수를 테이블 필드에 담을 수 있다. 그래서 테이블이 메소드를 가질 수도 있다. (3.4.11절 참고.)
테이블 인덱스는 언어의 raw 동일 정의를 따른다.
a[i]
와 a[j]
라는 식이 있을 때,
i
와 j
가 raw 동일(즉 메타메소드 빼고 동일)이면,
그리고 그 경우에만 두 식이 같은 테이블 항목을 나타낸다.
특별히 정수 값을 가진 실수는 대응하는 정수와 동일하다.
(예를 들어 1.0 == 1
이다.)
모호함을 피하기 위해
키로 정수 값의 실수를 쓰면
대응하는 정수로 변환된다.
예를 들어 a[2.0] = true
라고 작성하면
테이블에 들어가는 실제 키는 정수 2
가 된다.
(한편으로,
2와 "2
"는 서로 다른 루아 값이므로
각기 다른 테이블 항목을 나타낸다.)
테이블, 함수, 스레드, (full) userdata 값은 객체다. 변수가 이 값을 실제로 담는 게 아니라 참조할 뿐이다. 할당, 매개변수 전달, 함수 반환을 하면 언제나 그 값의 참조를 조작하는 것이며, 그 연산에 어떤 종류의 복사도 수반되지 않는다.
라이브러리 함수 type
은
주어진 값의 타입을 나타내는 문자열을 반환한다.
(6.1절 참고.)
3.2절과 3.3.3절에서 논의하겠지만
유휴 이름 (즉 어떤 선언에도 결속되지 않은 이름)
var
에 대한 참조는
_ENV.var
로 구문 변환된다.
그리고 _ENV
라는 외부 지역 변수의 유효 범위 안에서
각 청크를 컴파일하므로 (3.3.3절 참고)
청크 내에서 _ENV
자체는 절대 유휴 이름일 수 없다.
이런 외부 _ENV
변수의 존재와 유휴 이름 변환에도 불구하고
_ENV
는 특별할 것 없는 이름이다.
특히 그 이름으로 새 변수와 매개변수를 정의할 수 있다.
유휴 이름에 대한 각 참조에서는
루아의 일반적인 가시성 규칙에 따라서
그 프로그램 위치에서 보이는 _ENV
를 사용한다.
(3.5절 참고.)
_ENV
의 값으로 쓰는 테이블을 모두 환경(environment)이라고 부른다.
루아에서는 전역 환경이라는 특별한 환경을 둔다.
C 레지스트리의 특수 인덱스에 그 값을 유지한다. (4.5절 참고.)
그리고 같은 값으로 전역 변수 _G
를 초기화한다.
(_G
는 내부에서 절대 쓰지 않는다.)
루아에서 청크를 적재할 때
그 _ENV
upvalue의 기본값은 전역 환경이다.
(load
참고.)
따라서 기본적으로 루아 코드의 유휴 이름은
전역 환경 내의 항목들을 가리킨다.
(그래서 전역 변수라고도 한다.)
더불어 모든 표준 라이브러리가 전역 환경에 적재되고
그 함수들 일부가 그 환경 상에서 동작한다.
load
를 (또는 loadfile
을) 이용해
다른 환경으로 청크를 적재할 수 있다.
(C에서는 청크를 적재한 다음 그 첫 번째 upvalue의
값을 바꿔야 한다.)
루아는 내장식 확장 언어이므로
모든 루아 동작은 호스트 프로그램의 C 코드가
루아 라이브러리의 함수를 호출하는 것으로 시작한다.
(단독형 루아를 사용할 때는
lua
응용이 호스트 프로그램이다.)
루아 청크를 컴파일하거나 실행하는 도중에
오류가 발생하면
제어가 호스트로 되돌아간다.
거기서 (오류 메시지 찍기 같은)
적절한 대처를 할 수 있다.
루아 코드에서 error
함수를
호출해서 명시적으로 오류를 만들어 낼 수 있다.
루아 내에서 오류를 잡아야 하는 경우에는
pcall
이나 xpcall
을 사용해서
원하는 함수를 보호 모드로 호출할 수 있다.
오류가 있을 때마다 그 오류에 대한 정보를 담은 오류 객체가 (오류 메시지라고도 함) 전파된다. 루아 자체에서는 오류 객체가 문자열인 오류만 생성하지만 프로그램들에선 어떤 오류 객체 값으로도 오류를 생성할 수 있다. 그런 오류 객체를 처리하는 것은 그 루아 프로그램 내지 호스트의 몫이다.
xpcall
이나 lua_pcall
을 사용할 때
오류 발생 시 호출될
메시지 핸들러를 줄 수 있다.
그 함수는 원본 오류 객체로 호출되어
새 오류 객체를 반환한다.
오류 때문에 스택이 해제되기 전에 호출되므로
오류에 대해 더 많은 정보를 모을 수 있다.
예를 들어 스택을 조사하거나 스택 트레이스백을 만들 수 있다.
이 메시지 핸들러 자체도 보호 호출의 보호를 받으며,
그래서 메시지 핸들러 내에서 오류가 발생하면
다시 메시지 핸들러가 불리게 된다.
그 고리가 너무 길게 이어지면
루아에서 끊고서 적당한 메시지를 반환한다.
(정규 런타임 오류에만 메시지 핸들러가 호출된다.
메모리 할당 오류나 종료자 실행 중의 오류에는
호출되지 않는다.)
루아의 모든 값에는 메타테이블(metatable)이 있을 수 있다.
메타테이블은 평범한 루아 테이블이며
몇몇 특별한 연산들에서 기반 값의 동작을 규정한다.
메타테이블의 개별 필드를 설정해서
값에 대한 연산 동작의 여러 측면을 바꿀 수 있다.
예를 들어 수가 아닌 값이 덧셈의 피연산자일 때
루아에서는 그 값의 메타테이블에서
"__add
" 필드에 함수가 있는지 확인한다.
있으면 루아가 그 함수를 호출해서 덧셈을 수행한다.
메타테이블의 각 이벤트에 대한 키는
이벤트 이름 앞에 밑줄 두 개가 붙은 문자열이다.
그 키에 대응하는 값을 메타메소드(metamethod)라고 한다.
앞의 예에서 키는 "__add
"이고
메타메소드는 덧셈 수행 함수다.
따로 명시한 경우가 아니면
메타메소드는 함수 값이어야 한다.
getmetatable
함수를 이용해
원하는 값의 메타테이블을 질의할 수 있다.
루아에서는 raw 접근을 이용해 메타테이블 내의 메타메소드를 질의한다. (rawget
참고.)
따라서 객체 o
에서 이벤트 ev
에 대한 메타메소드를
얻으려 할 때 루아에서 하는 것은 다음 코드와 동등하다.
rawget(getmetatable(o) or {}, "__ev")
setmetatable
함수를 이용해
테이블의 메타테이블을 교체할 수 있다.
루아 코드에서는 (디버그 라이브러리 사용을 제외하면 (6.10절 참고))
다른 타입들의 메타테이블을 바꿀 수 없다.
그러려면 C API를 사용해야 한다.
테이블과 full userdata에는 개별적으로 메타테이블이 있다. (다만 여러 테이블 및 userdata가 메타테이블을 공유할 수도 있다.) 다른 타입 값들은 타입별로 하나씩 있는 메타테이블을 공유한다. 즉, 수 전체에 메타테이블 하나가 있고, 문자열 전체에 하나가 있고, 하는 식이다. 기본적으로는 값에 메타테이블이 없다. 하지만 문자열 라이브러리에서는 문자열 타입에 메타테이블을 설정한다. (6.4절 참고.)
메타테이블은 객체가 산술 연산, 비트 연산, 순서 비교, 접합, 길이 연산, 호출, 인덱스 사용에서 어떻게 동작할지를 제어한다. 또 userdata나 테이블이 쓰레기 수집 될 때 호출되는 함수를 메타테이블에 정의할 수도 있다. (2.5절 참고.)
단항 연산자(반수, 길이, 비트 NOT)에서는 두 번째 피연산자를 첫 번째와 같은 더미 값으로 채워서 메타메소드를 계산하고 호출한다. 이 추가 피연산자는 (그 연산자들이 이항 연산자처럼 동작하게 만들어서) 루아의 내부 동작을 단순하게 만들기 위한 것이며 향후 버전에서 제거될 수도 있다. (대부분 경우에 이 추가 피연산자는 별 의미가 없다.)
메타테이블로 제어하는 이벤트들의 자세한 목록이 다음에 있다. 해당 키로 각 연산을 식별한다.
__add
:
덧셈 (+
) 연산.
덧셈의 어느 피연산자라도 수가 아니면
(수로 강제할 수 있는 문자열도 아니면)
루아에서 메타메소드 호출을 시도하게 된다.
먼저 첫 번째 피연산자를 (유효하더라도) 확인한다.
그 피연산자에서 __add
에 대한 메타메소드를
정의하고 있지 않으면 두 번째 피연산자를 확인한다.
메타메소드를 찾을 수 있으면
루아에서 두 피연산자를 인자로 해서
그 메타메소드를 호출하며
(한 개 값으로 조정된) 호출 결과가
연산 결과가 된다.
그렇지 않으면 오류를 던진다.
__sub
:
뺄셈 (-
) 연산.
덧셈 연산과 비슷하게 동작.
__mul
:
곱셈 (*
) 연산.
덧셈 연산과 비슷하게 동작.
__div
:
나눗셈 (/
) 연산.
덧셈 연산과 비슷하게 동작.
__mod
:
모듈로 (%
) 연산.
덧셈 연산과 비슷하게 동작.
__pow
:
누승 (^
) 연산.
덧셈 연산과 비슷하게 동작.
__unm
:
반수 (단항 -
) 연산.
덧셈 연산과 비슷하게 동작.
__idiv
:
내림 나눗셈 (//
) 연산.
덧셈 연산과 비슷하게 동작.
__band
:
비트 AND (&
) 연산.
덧셈 연산과 비슷하게 동작하되,
정수도 아니고 정수로 강제 가능한 (3.4.3절 참고) 값도 아닌
피연산자가 하나라도 있으면
루아에서 메타메소드를 시도하게 된다.
__bor
:
비트 OR (|
) 연산.
비트 AND 연산과 비슷하게 동작.
__bxor
:
비트 배타적 OR (이항 ~
) 연산.
비트 AND 연산과 비슷하게 동작.
__bnot
:
비트 NOT (단항 ~
) 연산.
비트 AND 연산과 비슷하게 동작.
__shl
:
비트 왼쪽 시프트 (<<
) 연산.
비트 AND 연산과 비슷하게 동작.
__shr
:
비트 오른쪽 시프트 (>>
) 연산.
비트 AND 연산과 비슷하게 동작.
__concat
:
접합 (..
) 연산.
덧셈 연산과 비슷하게 동작하되,
문자열도 아니고 (항상 문자열로 강제하는) 수도 아닌
피연산자가 하나라도 있으면
루아에서 메타메소드를 시도하게 된다.
__len
:
길이 (#
) 연산.
객체가 문자열이 아니면
루아에서 메타메소드를 시도하게 된다.
메타메소드가 있으면
객체를 인자로 해서 호출하며
호출 결과가 (언제나 한 개 값으로 조정돼서)
연산 결과가 된다.
메타메소드가 없지만 객체가 테이블인 경우에는
루아에서 테이블 길이 연산을 사용한다. (3.4.7절 참고.)
그 외 경우에는 루아가 오류를 던진다.
__eq
:
같음 (==
) 연산.
덧셈 연산과 비슷하게 동작하되,
비교하려는 두 값이 모두 테이블이거나 모두 userdata이고
단순 비교로는 같지 않을 때만
루아에서 메타메소드를 시도하게 된다.
호출 결과가 항상 불리언으로 변환된다.
__lt
:
작음 (<
) 연산.
덧셈 연산과 비슷하게 동작하되,
비교하려는 두 값이
모두 수도 아니고 모두 문자열도 아닐 때만
루아에서 메타메소드를 시도하게 된다.
호출 결과가 항상 불리언으로 변환된다.
__le
:
작거나 같음 (<=
) 연산.
다른 연산들과 달리
작거나 같음 연산에서는 두 가지 이벤트를 사용할 수 있다.
먼저 루아에서는 작음 연산과 같은 방식으로
두 피연산자 모두에서 __le
메타메소드를 찾는다.
그런 메타메소드를 찾을 수 없는 경우에는
a <= b
가 not (b < a)
와 동등하다고 가정하고
__lt
메타메소드를 시도하게 된다.
다른 비교 연산자들처럼
결과가 항상 불리언이다.
(이렇게 __lt
이벤트를 쓰는 방식은 향후 버전에서 제거될 수 있다.
또한 진짜 __le
메타메소드보다 느리다.)
__index
:
인덱스 이용 접근 연산 table[key]
.
table
이 테이블이 아니거나
table
내에 key
가 없을 때
이 이벤트가 일어난다.
table
에서 메타메소드를 찾는다.
이름과 달리
이 이벤트에 대한 메타메소드는 함수일 수도 있고 테이블일 수도 있다.
함수인 경우
table
과 key
를 인자로 해서 호출하며
호출 결과가
(한 개 값으로 조정돼서)
연산 결과가 된다.
테이블인 경우
그 테이블에 key
를 인덱스로 쓴 결과가 최종 결과이다.
(이 인덱스 사용은 raw가 아니라 정규 방식이며,
따라서 또 다른 메타메소드를 동작시킬 수 있다.)
__newindex
:
인덱스 할당 table[key] = value
.
index 이벤트에서처럼
table
이 테이블이 아니거나
table
내에 key
가 없을 때
이 이벤트가 일어난다.
table
에서 메타메소드를 찾는다.
index에서처럼
이 이벤트에 대한 메타메소드는 함수일 수도 있고 테이블일 수도 있다.
함수인 경우
table
, key
, value
를 인자로 해서 호출한다.
테이블인 경우
같은 키와 값으로 그 테이블에 인덱스 할당을 한다.
(그 할당은 raw가 아니라 정규 방식이며,
따라서 또 다른 메타메소드를 동작시킬 수 있다.)
__newindex
메타메소드가 있을 때에는
루아가 절대 단순 할당을 수행하지 않는다.
(필요하면
메타메소드 자체에서 rawset
을 호출해서
직접 할당을 할 수 있다.)
__call
:
호출 연산 func(args)
.
루아에서 함수 아닌 값을 호출하려 할 때
(즉 func
가 함수가 아닐 때)
이 이벤트가 일어난다.
func
에서 메타메소드를 찾는다.
존재하는 경우
func
를 첫 번째 인자로 하고
이어서 원래 호출의 인자들(args
)이 오게 해서
메타메소드를 호출한다.
호출 결과 모두가 연산 결과가 된다.
(복수 개 결과를 허용하는 유일한 메타메소드이다.)
테이블을 어떤 객체의 메타테이블로 설정하기 전에
필요한 모든 메타메소드를 추가해 두는 게 좋다.
특히 __gc
메타메소드는 이 순서를 따를 때만
제대로 동작한다. (2.5.1절 참고.)
메타테이블도 정규 테이블이기 때문에
위에 밝힌 이벤트 이름뿐 아니라
임의의 필드를 담을 수 있다.
표준 라이브러리의 일부 함수들은
(예: tostring
)
메타테이블의 다른 필드들을 자체 용도로 이용한다.
루아는 자동 메모리 관리를 수행한다. 즉, 새 객체를 위해 메모리를 할당하는 것이나 그 객체가 더는 필요 없을 때 해제하는 것에 대해 신경 쓸 필요가 없다. 루아에서 쓰레기 수집기를 실행해 죽은 객체를 (즉 루아에서 더 이상 접근할 수 없는 객체를) 모두 수집하는 방식으로 메모리를 자동 관리한다. 문자열, 테이블, userdata, 함수, 스레드, 내부 구조체 등, 루아에서 사용하는 모든 메모리가 자동 관리 대상이다.
루아에서는 점진식 mark-and-sweep 수집기를 구현하고 있다. 쓰레기 수집 사이클을 제어하는 두 가지 수치가 있는데, 쓰레기 수집 휴지 시간과 쓰레기 수집 단계 비율이다. 둘 다 백분률 단위이다. (가령 100 값이 내부적으로 1 값을 뜻한다.)
쓰레기 수집 휴지 시간은 수집기가 얼마나 오래 기다렸다가 새 주기를 시작할지 제어한다. 값이 크면 수집기가 덜 적극적이 된다. 100보다 작은 값은 기다리지 않고 새 주기를 시작하는 걸 뜻한다. 200 값은 총 사용 메모리가 두 배가 될 때까지 기다렸다가 새 주기를 시작한다는 뜻이다.
쓰레기 수집 단계 비율은 메모리 할당 대비 수집기의 상대 속도를 제어한다. 값이 크면 수집기가 더 적극적이 되며 또 각 점진 단계가 더 커진다. 100보다 작은 값은 사용하지 않는 게 좋다. 수집기가 너무 느려지며 수집기가 사이클을 절대 마치지 못하게 될 수 있기 때문이다. 기본은 200인데, 메모리 할당 속도의 "두 배"로 수집기가 돈다는 뜻이다.
단계 비율을 아주 큰 수로 (프로그램에서 사용할 수 있는 최대 바이트 수의 10% 이상으로) 설정하면 수집기가 stop-the-world 수집기처럼 동작한다. 거기서 휴지 시간을 200으로 설정하면 루아 이전 버전들처럼 수집기가 동작하게 된다. 즉, 루아의 메모리 사용량이 두 배가 될 때마다 전체 수집을 한다.
C에서 lua_gc
를 호출하거나
루아에서 collectgarbage
를 호출해서
이 수치들을 바꿀 수 있다.
그 함수들을 사용해 수집기를 직접 제어할 수도
(예를 들어 멈추거나 다시 시작할 수도) 있다.
테이블에, 그리고 C API로 full userdata에도 쓰레기 수집 메타메소드를 설정할 수 있다. (2.4절 참고.) 이 메타메소드들을 종료자(finalizer)라고도 한다. 종료자를 이용하면 루아의 쓰레기 수집을 (파일이나 네트워크 내지 데이터베이스 연결 닫기, 자체 메모리 해제 같은) 외부 자원 관리에 연계할 수 있다.
수집 때 마무리 작업이 필요한 객체(테이블이나 userdata)에는
마무리를 하라는 표시를 해 주어야 한다.
객체에 메타테이블을 설정하는데 그 메타테이블에
문자열 "__gc
"가 인덱스인 필드가 있으면
객체에 마무리 표시를 하는 것이다.
참고로 __gc
필드 없는 메타테이블을 설정하고서
나중에 메타테이블에 그 필드를 만들어도
객체에 마무리 표시가 되지 않는다.
표시가 붙은 객체가 쓰레기가 될 때는
쓰레기 수집기가 즉시 수집하지 않는다.
대신 루아에서 어떤 목록에 그 객체를 넣어 둔다.
그리고 수집 후에 그 목록을 살펴본다.
목록의 각 객체마다
객체의 __gc
메타메소드를 확인한다.
함수이면
그 객체를 단일 인자로 해서 호출한다.
메타메소드가 함수가 아니면
그냥 무시한다.
각 쓰레기 수집 사이클 마지막에서 그 주기에 수집한 객체들에 대해 마무리 표시를 한 것과 반대 순서로 객체의 종료자를 호출한다. 즉, 처음 호출되는 종료자는 프로그램에서 마지막으로 표시한 객체에 연계된 종료자다. 종료자 실행은 정규 코드 실행 중의 어느 시점에서든 이뤄질 수 있다.
수집 중인 객체를 종료자에서 계속 사용해야 하기 때문에 그 객체를 (그리고 그 객체를 통해서만 접근 가능한 다른 객체들을) 루아에서 부활시켜야 한다. 일반적으로 이 부활은 일시적이며 다음 쓰레기 수집 주기에 그 객체 메모리가 해제된다. 하지만 종료자에서 그 객체를 어떤 전역 위치에 (가령 전역 변수에) 저장한다면 부활이 영구적이 된다. 그리고 종료자에서 마무리 중인 객체에 다시 마무리 표시를 하면 그 객체가 도달 불가능하게 되는 다음번 주기에 종료자가 호출된다. 어찌 됐든, 객체가 도달 불가능이고 마무리 표시가 되어 있지 않은 GC 주기에서만 객체 메모리가 해제된다.
상태를 닫을 때 (lua_close
참고)
루아에서는 마무리 표시가 된 모든 객체의 종료자를
표시 반대 순서로 호출한다.
그 단계에서 어느 종료자가 객체에 수집 표시를 하더라도
그 표시는 아무 효과가 없다.
약한 테이블이란 약한 참조가 원소인 테이블이다. 약한 참조는 쓰레기 수집 시 무시된다. 다시 말해 어느 객체에 대한 참조가 약한 참조뿐이면 쓰레기 수집기가 그 객체를 수집하게 된다.
약한 테이블은 키가 약할 수도 있고, 값이 약할 수도 있고,
둘 모두 약할 수도 있다.
값이 약한 테이블은 값이 수집되는 것은 허용하지만
키가 수집되는 것은 막는다.
키와 값 모두 약한 테이블은
키와 값 모두의 수집을 허용한다.
어느 경우든 키나 값이 수집되면
그 쌍이 통째로 테이블에서 제거된다.
테이블 메타테이블의 __mode
필드로
테이블의 약함 방식을 제어한다.
__mode
필드가 문자 'k
'를 담은 문자열이면
그 테이블의 키가 약하다.
__mode
가 'v
'를 담고 있으면
그 테이블의 값이 약하다.
키가 약하고 값이 강한 테이블을 이페머론(ephemeron) 테이블이라고도 한다. 이페머론 테이블에서는 키가 도달 가능한 경우에만 그 값이 도달 가능하다고 본다. 특히 어느 키에 대한 유일한 참조가 그 값을 통한 것이면 그 쌍을 제거한다.
테이블의 약함 방식을 변경한 효과가 다음 수집 주기에서야 나타날 수도 있다. 특히 강한 방식으로 바꾸는 경우에는 변경 효과가 나타나기 전까지 루아에서 그 테이블의 일부 항목을 계속 수집할 수도 있다.
명시적 생성을 하는 객체만 약한 테이블에서 제거된다. 수나 경량 C 함수 같은 값은 쓰레기 수집 대상이 아니고, 따라서 (연계된 값이 수집되지 않는 한) 약한 테이블에서 제거되지 않는다. 문자열은 쓰레기 수집의 대상이지만 명시적 생성을 하지 않으며, 따라서 약한 테이블에서 제거되지 않는다.
부활한 객체는 (즉 마무리 중인 객체 및 마무리 중인 객체를 통해서만 접근 가능한 객체는) 약한 테이블에서 특별한 방식으로 다룬다. 약한 값 때문에 제거될 때는 종료자 실행 전에 제거되지만 약한 키 때문에 제거될 때는 종료자 실행 후에 그 객체가 실제로 해제되는 다음 주기에서야 제거된다. 이런 동작 덕분에 종료자에서 약한 테이블을 통해 객체에 연계된 자원에 접근할 수 있다.
어느 수집 주기에 부활한 객체들 중에 약한 테이블이 있는 경우 다음 주기까지 그 테이블이 완전히 사라지지 않을 수도 있다.
루아는 협력적 멀티스레딩이라고도 하는 코루틴을 지원한다. 루아에서 코루틴은 독립적 실행 흐름을 나타낸다. 하지만 멀티스레드 시스템의 스레드와 달리 코루틴은 명시적인 양보 함수 호출을 통해서만 실행을 멈춘다.
coroutine.create
를 호출해서 코루틴을 만든다.
유일한 인자는 함수이고 그게 코루틴의 메인 함수다.
create
함수는 새 코루틴을 만들어서
핸들(스레드 타입 객체)을 반환하기만 한다.
즉, 코루틴을 시작하지는 않는다.
coroutine.resume
을 호출해서 코루틴을 실행한다.
coroutine.create
가 반환한 스레드를
첫 번째 인자로 해서
처음으로 coroutine.resume
을 호출할 때
코루틴이 자기 메인 함수를 호출하며 실행을 시작한다.
coroutine.resume
으로 전달한 추가 인자들이
그 함수의 인자로 전달된다.
코루틴이 실행을 시작하고 나면
종료하거나 양보(yield)할 때까지 돈다.
코루틴은 두 가지 방식으로 실행을 끝마칠 수 있다.
메인 함수가 (명시적으로, 또는 마지막 인스트럭션 후에 암묵적으로) 반환할 때
정상적으로 종료하거나,
보호 안 된 오류가 있을 때 비정상적으로 종료한다.
정상 종료인 경우
coroutine.resume
이 true를, 그리고
코루틴 메인 함수가 반환한 값들이 있으면 함께 반환한다.
오류 발생 시 coroutine.resume
이 false를, 그리고
오류 객체를 반환한다.
coroutine.yield
를 호출해서 코루틴이 실행을 양보한다.
코루틴이 양보하면
대응하는 coroutine.resume
이 즉시 반환한다.
중첩 함수 호출 안에서
(즉 메인 함수 안이 아니라 메인 함수에서 직간접으로 호출한 함수 안에서)
양보가 이뤄질 때도 마찬가지이다.
양보하는 경우 coroutine.resume
이 true를, 그리고
coroutine.yield
에 전달한 값들이 있으면 함께 반환한다.
같은 코루틴을 다음에 재개할 때는
양보했던 지점에서 실행이 이어지며,
coroutine.resume
에 전달한 추가 인자들이 있으면
coroutine.yield
호출이 반환한다.
coroutine.create
와 마찬가지로
coroutine.wrap
함수도 코루틴을 만든다.
하지만 코루틴 자체를 반환하는 것이 아니라
함수를 반환하며, 그 함수 호출 시 코루틴이 재개된다.
그 함수로 전달한 인자들이 있으면
coroutine.resume
추가 인자가 된다.
coroutine.wrap
은 coroutine.resume
이 반환한 값들을
첫 번째 값(불리언 오류 코드)만 빼고
전부 반환한다.
coroutine.resume
과 달리
coroutine.wrap
은 오류를 잡지 않는다.
즉, 오류가 생기면 호출자에게 전파된다.
코루틴 동작 방식에 대한 예로 다음 코드를 살펴보자.
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
함수를 보라.
이 절에서는 루아의 어휘, 문법, 의미론을 기술한다. 다시 말해 어떤 토큰들이 유효한지, 그 토큰들을 어떻게 결합할 수 있는지, 그리고 그 조합이 무엇을 뜻하는지 설명한다.
흔히 하듯 확장 BNF 표기법을 이용해 언어 구성 요소들을 설명할 것이다. {a}는 a가 0개나 그보다 많이 있다는 뜻이고 [a]는 a가 선택적이라는 뜻이다. 비말단 심볼은 글꼴 꾸밈 없이 표시하며, 키워드는 kword처럼 표시하고, 다른 말단 심볼들은 ‘=’처럼 표시한다. 루아의 전체 문법을 이 매뉴얼 마지막의 9절에서 볼 수 있다.
루아는 자유 형식 언어다. 이름 및 키워드들 사이 구분자 역할을 제외하면 어휘 요소(토큰)들 사이의 (개행 포함) 공백과 주석을 무시한다.
루아에서 이름(식별자라고도 함)은 글자, 숫자, 밑줄로 이뤄진 어떤 열도 가능하되, 숫자로 시작할 수 없고 예약 단어가 아니어야 한다. 변수, 테이블 필드, 레이블을 지칭하는 데 식별자를 쓴다.
다음 키워드는 예약되어 있어서 이름으로 쓸 수 없다.
and break do else elseif end false for function goto if in local nil not or repeat return then true until while
루아는 대소문자를 구별하는 언어다.
그래서 and
는 예약 단어지만
And
와 AND
는 그와 다른 유효한 이름이다.
관행 상
밑줄로 시작하고 이어서 한 개 이상의 대문자가 오는
(_VERSION
같은) 이름을
프로그램에서 만들지 않는 게 좋다.
다음이 나머지 토큰들을 나타낸다.
+ - * / % ^ # & ~ | << >> // == ~= <= >= < > = ( ) { } [ ] :: ; : , . .. ...
짝이 맞는 작은따옴표나 큰따옴표로 감싸서
짧은 리터럴 문자열을 만들 수 있다.
그 문자열에
'\a
' (벨),
'\b
' (백스페이스),
'\f
' (폼 피드),
'\n
' (개행),
'\r
' (캐리지 리턴),
'\t
' (수평 탭),
'\v
' (수직 탭),
'\\
' (백슬래시),
'\"
' (큰따옴표),
'\'
' (작은따옴표)
같은 C 스타일 이스케이프 열이 포함될 수 있다.
백슬래시 다음에 행이 바뀌면
문자열 내에서 개행이 된다.
이스케이프 열 '\z
'는
행 바꿈을 포함해서
이어지는 공백 문자들 구간을 건너뛰게 한다.
긴 리터럴 문자열을
내용에 개행이나 공백을 더하지 않으면서
여러 행으로 쪼개거나 들여 쓰는 데
유용하게 이용할 수 있다.
짧은 리터럴 문자열에는
이스케이프 안 된 줄 바꿈이나
유효한 이스케이프 열이 아닌 이스케이프가 포함될 수 없다.
짧은 리터럴 문자열 내 임의 바이트를
(0을 포함해서)
숫자 값으로 지정할 수 있다.
이스케이프 열 \xXX
를 쓰는데,
여기서 XX는 정확히 두 개의 16진수 열이다.
또는 이스케이프 열 \ddd
를 쓰는데,
여기서 ddd는 세 개까지의 10진수 열이다.
(참고로 10진 이스케이프 열에 이어서 숫자가 오는 경우에는
정확히 세 개 숫자로 표현해야 한다.)
이스케이프 열 \u{XXX}
를 이용해
UTF-8 인코딩 유니코드 문자를
리터럴 문자열에 집어넣을 수 있다.
(감싸는 중괄호가 필수다.)
여기서 XXX는 문자 코드 포인트를 나타내는
한 개 이상의 16진수 열이다.
긴 괄호로 감싸는 긴 형식을 이용해
리터럴 문자열을 정의할 수도 있다.
먼저 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진수 지수와 함께 쓸 수 있다.
0x
나 0X
로 시작하는
16진수 상수도 받는다.
16진수 상수에서도 선택적으로 소수 부분이나
'p
' 내지 'P
' 글자로 표시한
2진수 지수를 받는다.
소수점이나 지수가 있는 숫자 상수는
실수를 나타낸다.
그렇지 않고
값이 정수 범위에 들어가면
정수를 나타낸다.
다음은 유효한 정수 상수의 예이다.
3 345 0xff 0xBEBADA
다음은 유효한 실수 상수의 예이다.
3.0 3.1416 314.16e-2 0.31416E1 34e1 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
문자열 밖 어디서든 하이픈 두 개(--
)로
주석이 시작된다.
--
바로 다음 텍스트가 여는 긴 괄호가 아니면
그 주석은 짧은 주석이고
그 행 끝까지 이어진다.
맞으면 긴 주석이고
대응하는 닫는 긴 괄호까지 이어진다.
긴 주석은 코드를 임시로 비활성화하는 데 자주 쓰인다.
변수는 값을 저장하는 장소다. 루아에는 세 가지 변수가 있는데, 전역 변수, 지역 변수, 그리고 테이블 필드다.
한 이름이 전역 변수 또는 지역 변수를 (또는 지역 변수의 한 종류인 함수의 형식 매개변수를) 나타낼 수 있다.
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절 참고.)
루아에서는 파스칼이나 C와 비슷한 거의 관행적인 문(statement)들을 지원한다. 할당, 제어 구조, 함수 호출, 변수 선언 등을 포함한다.
블록은 순차적으로 실행되는 문들의 목록이다.
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절 참고.)
루아의 컴파일 단위를 청크(chunk)라고 부른다. 문법적으로 청크는 그냥 블록이다.
chunk ::= block
루아에서는 청크를
이름 없는 가변 인자 함수의 몸체인 것처럼 다룬다.
(3.4.11절 참고.)
그렇기에 청크에서 지역 변수를 정의할 수 있고,
인자를 받고 값을 반환할 수 있다.
그리고 그 익명 함수가
_ENV
라는 외부 지역 변수의 유효 범위 안에
있는 것으로 해서 컴파일한다.
그래서 그 함수에는 이용 여부와 상관없이 언제나
유일한 upvalue _ENV
가 있다.
(2.2절 참고.)
파일에, 또는 호스트 프로그램 내 문자열에 청크를 저장할 수 있다. 실행을 위해선 먼저 루아에서 청크를 적재하는데, 청크의 코드를 가상 머신 인스트럭션으로 사전 컴파일한다. 그러고서 컴파일된 코드를 가상 머신 인터프리터로 실행한다.
청크를 바이너리 형태로 사전 컴파일해 둘 수도 있다.
자세한 내용은 luac
프로그램과 string.dump
함수를 보라.
소스 형태 프로그램과 컴파일 형태 프로그램은 서로 대체 가능하다.
루아가 파일 종류를 자동으로 탐지해서 그에 맞게 동작한다.
(load
참고.)
루아에서는 다중 할당이 가능하다. 그래서 할당 문법에서 왼쪽에 변수 목록이 오고 오른쪽에 식 목록이 온다. 두 목록 모두 쉼표로 항목을 구분한다.
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
x
와 y
의 값을 교환한다. 그리고 다음은
x, y, z = y, z, x
x
, y
, z
의 값을 순환시킨다.
전역 이름에 대한 할당 x = val
은
할당 _ENV.x = val
과 동등하다.
(2.2절 참고.)
테이블 필드와 (실제로는 역시 테이블 필드인) 전역 변수에 대한 할당의 의미를 메타테이블을 통해 바꿀 수 있다. (2.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절 참고.)
제어 구조의 조건 식은 어떤 값이든 반환할 수 있다. false와 nil은 거짓으로 본다. nil과 false 외의 모든 값은 참으로 본다. (특히 수 0과 빈 문자열도 참이다.)
repeat–until 루프에서 내부 블록은 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이 (안쪽) 블록의 마지막 문이 되기 때문이다.
for 문에는 수열형과 일반형, 두 가지 형태가 있다.
수열형 for 루프는 제어 변수가 등차수열을 거치는 동안 코드 블록을 반복한다. 문법은 다음과 같다.
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
name이 첫 번째 exp 값으로 시작해서 세 번째 exp씩 진행해서 두 번째 exp를 지날 때까지 block을 반복한다. 더 엄밀하게는 다음 for 문이
for v = e1, e2, e3 do block end
다음 코드와 동등하다.
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end var = var - step while true do var = var + step if (step >= 0 and var > limit) or (step < 0 and var < limit) then break end local v = var block end end
다음에 유의해야 한다.
var
, limit
, step
은 보이지 않는 변수다.
여기 나와 있는 이름은 설명을 위한 것이다.
v
는 루프 몸체에 국한된 변수다.
루프 다음에 그 값이 필요하다면
루프에서 나가기 전에 다른 변수에 할당해 두면 된다.
일반형 for 문은 반복자(iterator)라는 함수를 기반으로 동작한다. 각 반복마다 반복자 함수를 호출해서 새 값을 만들어 내며, 그 새 값이 nil이면 멈춘다. 일반형 for 루프의 문법은 다음과 같다.
stat ::= for namelist in explist do block end namelist ::= Name {‘,’ Name}
다음 for 문이
for var_1, ···, var_n in explist do block end
다음 코드와 동등하다.
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) if var_1 == nil then break end var = var_1 block end end
다음에 유의해야 한다.
explist
를 단 한 번 평가한다.
그 결과는 반복자 함수,
상태,
반복자 변수 초기 값이다.
f
, s
, var
은 보이지 않는 변수다.
여기의 이름은 설명을 위한 것이다.
var_i
는 루프에 국한된 변수다.
for가 끝난 후에 그 값을 쓸 수 없다.
그 값이 필요하다면
루프에서 나가기 전에 다른 변수에 할당해 두면 된다.
부대 효과를 위해서 함수 호출을 문으로 실행할 수 있다.
stat ::= functioncall
이 경우 반환되는 값은 모두 버린다. 함수 호출을 3.4.10절에서 설명한다.
블록 내 어디에서도 지역 변수를 선언할 수 있다. 선언에 초기 할당이 포함될 수 있다.
stat ::= local namelist [‘=’ explist]
초기 할당이 있는 경우 다중 할당과 동작 방식이 같다. (3.3.3절 참고.) 아니라면 모든 변수가 nil로 초기화된다.
청크도 블록이므로 (3.3.2절 참고) 청크 안의 명시적 블록 밖에서 지역 변수를 선언할 수 있다.
지역 변수 가시성 규칙을 3.5절에서 설명한다.
루아의 기본 식(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.3절 참고) 실수로 변환한다. 일반적인 실수 산술 규칙(보통 IEEE 754 표준)에 따라 연산을 수행하며 결과가 실수다.
누승과 실수 나눗셈(/
)은
피연산자를 항상 실수로 변환하며
결과가 항상 실수이다.
누승에 ISO C 함수 pow
를 사용하므로
정수 아닌 지수도 가능하다.
내림 나눗셈(//
)은
몫을 음의 무한대 쪽으로 내림하는 나눗셈이다.
즉 피연산자들로 나눗셈 한 값의 바닥(floor) 값이다.
모듈로는 몫을 음의 무한대 쪽으로 내림하는 나눗셈(내림 나눗셈)의 나머지로 정의한다.
정수 산술에서 넘침이 발생하는 경우 모든 연산에서 일반적인 2의 보수 산술 규칙에 따라 값이 되감긴다. (다시 말해 수학적 결과와 모듈로 264로 같은 표현 가능한 유일한 정수를 반환한다.)
루아에서는 다음 비트 연산자를 지원한다.
&
: 비트 AND|
: 비트 OR~
: 비트 배타적 OR>>
: 오른쪽 시프트<<
: 왼쪽 시프트~
: 단항 비트 NOT모든 비트 연산은 피연산자를 정수로 변환하여 (3.4.3절 참고) 그 정수의 모든 비트에 대해 동작하며 결과가 정수다.
오른쪽 시프트와 왼쪽 시프트 모두 비는 비트를 0으로 채운다. 변위가 음수면 반대 방향으로 민다. 변위의 절대값이 정수의 비트 수와 같거나 그보다 크면 (모든 비트가 밀리므로) 결과가 0이다.
루아에서는 일부 타입과 표현들 간에 런타임 자동 변환을 어느 정도 제공한다. 비트 연산자는 항상 실수 피연산자를 정수로 변환한다. 누승과 실수 나눗셈에서는 항상 정수 피연산자를 실수로 변환한다. 다른 모든 산술 연산은 정수와 실수가 섞인 수들에 적용 시 정수 피연산자를 실수로 변환한다. 이를 일반 규칙이라고 한다. C API에서도 필요에 따라 정수를 실수로, 또는 실수를 정수로 변환한다. 그리고 문자열 접합에서는 문자열 외에도 수를 인자로 받는다.
또한 수를 기대하는 곳에서는 문자열을 수로 변환한다.
정수에서 실수로 변환 시 정수 값을 실수로 정확히 표현할 수 있으면 그 실수 표현이 결과가 된다. 그렇지 않으면 표현 가능한 가장 가까운 위나 아래의 값으로 변환한다. 이 변환은 절대 실패하지 않는다.
실수에서 정수로 변환할 때는 실수를 정수로 정확히 표현할 수 있는지 (즉 실수가 정수인 값을 가지고 있고 그 값이 정수 표현 범위 내에 있는지) 확인한다. 그렇다면 그 정수 표현이 결과가 된다. 아니면 변환에 실패한다.
문자열에서 수로 변환할 때는 먼저 문자열을 그 구문과 루아 단어 분석기(lexer) 규칙에 따라 정수나 실수로 변환한다. (문자열에 앞뒤의 공백과 부호가 있을 수 있다.) 그렇게 나온 수(실수 또는 정수)를 그 맥락(예를 들면 변환을 강제하는 연산)에서 요구하는 타입(실수 또는 정수)으로 변환한다.
문자열에서 수로 변환 시 소수점으로 마침표와 더불어 현재 로캘의 표시도 받아들인다. (하지만 루아 단어 분석기는 마침표만 받는다.)
수에서 문자열로 변환할 때는
따로 명세가 없는 사람이 읽을 수 있는 형식을 사용한다.
수가 문자열로 변환되는 방식을 완전히 제어하려면
문자열 라이브러리의 format
함수를 사용하면 된다.
(string.format
참고.)
루아에서는 다음 관계 연산자를 지원한다.
==
: 같음~=
: 같지 않음<
: 작음>
: 큼<=
: 작거나 같음>=
: 크거나 같음이 연산자들은 항상 false 또는 true를 내놓는다.
같음(==
)에서는 먼저 피연산자 타입을 비교한다.
타입이 다르면 결과가 false다.
그렇지 않으면 피연산자들의 값을 비교한다.
문자열은 자명한 방식으로 비교한다.
수는 같은 수학적 값을 나타내면 서로 같은 것이다.
테이블, userdata, 스레드는 참조로 비교한다. 즉, 두 객체는 동일 객체인 경우에만 서로 같다고 본다. 그래서 새 객체(테이블, userdata, 스레드)를 만들 때마다 그 새 객체는 이전의 모든 객체와 다르게 된다. 클로저는 그 자체와는 항상 같다. 탐지 가능한 차이(상이한 동작, 상이한 정의)가 있는 클로저는 항상 서로 다르다. 따로 생성되었지만 탐지 가능한 차이가 없는 클로저는 (내부 캐싱 세부 동작에 따라) 같다고 분류될 수도 있고 아닐 수도 있다.
"eq" 메타메소드를 이용하면 테이블과 userdata를 비교하는 방식을 바꿀 수 있다. (2.4절 참고.)
같음 비교에서는 문자열을 수로, 또는 그 반대로 변환하지 않는다.
따라서 "0"==0
을 평가하면 false이고,
t[0]
과 t["0"]
은
서로 다른 테이블 항목을 나타낸다.
연산자 ~=
는 같음(==
)의 정확히 반대다.
순서 연산자의 동작 방식은 이렇다.
두 인자 모두 수이면
(서브타입과 상관없이)
수학적 값에 따라 비교한다.
그렇지 않고 두 인자 모두 문자열이면
현재 로캘에 따라 그 값을 비교한다.
그 외 경우에는 메타메소드 "lt"나 "le" 호출을 시도한다.
(2.4절 참고.)
비교 식 a > b
는 b < a
로 바뀌고
a >= b
는 b <= a
로 바뀐다.
IEEE 754 표준에 따라 NaN은 (스스로를 포함한) 어떤 값보다 작지도, 같지도, 크지도 않다고 본다.
루아의 논리 연산자는 and, or, not이다. 제어 구조와 마찬가지로 (3.3.4절 참고) 논리 연산자에서는 false와 nil을 거짓으로 여기고 그 외는 모두 참으로 여긴다.
부정 연산자 not은 항상 false 또는 true를 반환한다. 논리곱 연산자 and는 첫 번째 인자의 값이 false나 nil이면 그 인자를 반환하고, 그렇지 않으면 두 번째 인자를 반환한다. 논리합 연산자 or는 첫 번째 인자의 값이 nil 및 false와 다르면 그 인자를 반환하고, 그렇지 않으면 두 번째 인자를 반환한다. and와 or 모두에서 단락 평가 방식을 쓴다. 즉, 필요한 경우에만 두 번째 피연산자를 평가한다. 몇 가지 예를 들면 다음과 같다.
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.3절에서 기술하는 규칙에 따라
문자열로 변환한다.
그렇지 않으면 메타메소드 __concat
을 호출한다.
(2.4절 참고.)
길이 연산자는 단항 전위 연산자 #
로 표시한다.
문자열의 길이는 문자열의 바이트 수이다. (즉, 각 문자가 한 바이트일 때 일반적인 문자열 길이와 같은 의미다.)
테이블에 길이 연산자를 적용하면
그 테이블의 경계를 반환한다.
테이블 t
의 경계(border)란
다음 조건을 충족시키는 자연수다.
(border == 0 or t[border] ~= nil) and t[border + 1] == nil
다시 말해 경계란 테이블에서 바로 다음에 nil 값이 오는 nil 아닌 값의 (자연수) 인덱스이다. (인덱스 1이 nil이면 0이다.)
경계가 딱 한 개인 테이블을 열(sequence)이라고 한다.
예를 들어 테이블 {10, 20, 30, 40, 50}
은
경계가 하나뿐(5)이므로 열이다.
테이블 {10, 20, 30, nil, 50}
은
경계가 둘(3과 5)이므로 열이 아니다.
테이블 {nil, 20, 30, nil, nil, 60, nil}
은
경계가 셋(0, 3, 6)이므로 역시 열이 아니다.
테이블 {}
는
경계가 0인 열이다.
참고로 자연수 아닌 키는
테이블이 열인지 여부에 영향을 주지 않는다.
t
가 열일 때
#t
는 그 유일한 경계를 반환한다.
그 값은 열의 길이라는 직관적 개념에 대응한다.
t
가 열이 아닐 때
#t
는 그 경계들 중 아무 값이나 반환할 수 있다.
(정확히 어느 값인지는
테이블을 내부적으로 표현하는 방식에 따라 달라지는데,
그 역시 테이블을 어떻게 채웠는지와
수 아닌 키들의 메모리 주소에 따라 달라질 수 있다.)
테이블 길이 계산의 최악 실행 시간이 O(log n)이라고 보장된다. 여기서 n은 테이블에서 가장 큰 자연수 키이다.
프로그램에서 메타메소드 __len
을 통해
문자열을 제외한 모든 값의 길이 연산자 동작을 바꿀 수 있다.
(2.4절 참고.)
루아의 연산자 우선순위는 아래 표를 따른다. 우선도가 점점 높아지는 순서다.
or and < > <= >= ~= == | ~ & << >> .. + - * / // % 단항 연산자 (not # - ~) ^
언제나처럼
괄호를 써서 식의 우선순위를 바꿀 수 있다.
접합('..
') 및 누승('^
') 연산자는
우측부터 결합이다.
다른 이항 연산자는 모두 좌측부터 결합이다.
테이블 생성자는 테이블을 만드는 식이다. 생성자를 평가할 때마다 새 테이블이 만들어진다. 생성자를 이용해 빈 테이블을 만들 수도 있고 테이블을 만들면서 일부 필드를 초기화할 수도 있다. 생성자의 일반 문법은 다음과 같다.
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절 참고.)
필드 목록 끝에 선택적으로 구분자가 올 수 있는데, 그래서 코드를 자동 생성하기가 편해진다.
루아에서 함수 호출의 문법은 다음과 같다.
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) return x, f(x) -- 결과에 추가 f(x); return -- 결과를 버림 return x or f(x) -- 결과 1개로 조정
함수 정의 문법은 다음과 같다.
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
루아는 문법적 스코프(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
변수를 쓴다.
이 절에서는 루아의 C API를 설명한다.
호스트 프로그램에서 루아와 의사소통하는 데 이 C 함수들을 이용할 수 있다.
모든 API 함수와 관련 타입 및 상수들이
헤더 파일 lua.h
에 선언되어 있다.
API의 어떤 항목이든 "함수"라는 용어를 쓰더라도 실제로는 매크로일 수 있다. 따로 언급하지 않으면 그런 매크로에서는 각 인자를 정확히 한 번만 사용하며 (언제나 루아 상태인 첫 번째 인자는 제외) 그래서 숨겨진 부작용을 전혀 만들어 내지 않는다.
대부분의 C 라이브러리들처럼
루아 API 함수에서도 인자의 유효성이나 무모순성을 검사하지 않는다.
하지만 매크로 LUA_USE_APICHECK
를 정의해서
루아를 컴파일하여 이 동작 방식을 바꿀 수 있다.
루아 라이브러리는 완전하게 재진입 가능하다. 즉, 전역 변수가 전혀 없다. 필요한 정보는 모두 루아 상태라고 하는 동적 구조체 안에 둔다.
각 루아 상태에는 한 개 이상의 스레드가 있는데,
각 스레드는 독립적인 협력적 실행 흐름에 대응한다.
lua_State
타입은 (그 이름과 달리) 스레드를 가리킨다.
(그 스레드를 통해서 연계된 루아 상태를
간접적으로 가리키기는 한다.)
라이브러리의 모든 함수에 첫 번째 인자로 스레드 포인터를 주어야 한다.
단, 무에서부터 루아 상태를 만들어서
새 상태의 주 스레드에 대한 포인터를 반환하는
lua_newstate
는 예외다.
가상 스택을 이용해 루아와 C가 값을 주고받는다. 이 스택의 각 항목이 루아 값(nil, 수, 문자열 등)을 나타낸다. API 함수들에 주는 루아 상태 매개변수를 통해 함수에서 이 스택에 접근할 수 있다.
루아에서 C를 호출할 때마다 피호출 함수가 새 스택을 받는다.
이 스택은 이전의 스택과, 그리고 아직 활성인 C 함수의 스택과 독립적이다.
처음에 이 스택은 C 함수를 위한 인자들을 담고 있다.
C 함수에서 여기에 임시 루아 값을 저장할 수 있으며
호출자에게 반환할 결과를 여기 집어넣어야 한다.
(lua_CFunction
참고.)
편의를 위해 API의 대다수 질의 연산에서는 스택 접근을 엄격하게 규제하지 않는다. 인덱스를 써서 스택 내의 어느 항목이든 참조할 수 있다. 양수 인덱스는 절대적 스택 위치를 나타내고 (1에서 시작), 음수 인덱스는 스택 상단을 기준으로 한 위치를 나타낸다. 구체적으로 스택에 n개 항목이 있을 때 인덱스 1은 첫 번째 항목을 (즉 스택에 가장 먼저 넣은 항목을) 나타내고 인덱스 n이 마지막 항목을 나타낸다. 인덱스 -1 역시 마지막 항목을 (즉 상단의 항목을) 나타내고 인덱스 -n이 첫 번째 항목을 나타낸다.
루아 API를 다룰 때
무모순성을 보장할 책임은 사용자에게 있다.
특히 스택 오버플로우를 책임지고 통제해야 한다.
함수 lua_checkstack
을 사용해서
스택에 새 항목을 집어넣을 공간이 있도록 할 수 있다.
루아에서 C를 부를 때는 항상
스택에 최소 LUA_MINSTACK
개의
추가 슬롯이 있도록 보장한다.
LUA_MINSTACK
은 20으로 정의되어 있으며,
따라서 코드에서 루프를 돌며 스택에 항목을 넣는 경우가 아니면
일반적으로 스택 공간에 신경 쓸 필요가 없다.
결과 개수가 정해져 있지 않은 루아 함수를 호출할 때
(lua_call
참고)
스택에 전체 결과를 위한 공간이 있도록 루아에서 보장하지만
그 이상의 공간은 보장하지 않는다.
따라서 그런 호출 후 스택에 뭔가를 집어넣기 전에는
lua_checkstack
을 쓰는 게 좋다.
API에서 스택 인덱스를 받는 함수는 모두 유효 인덱스 또는 허용 인덱스로 동작한다.
유효 인덱스란 변경 가능한 루아 값을
저장하고 있는 위치를 가리키는 인덱스다.
1번에서 스택 상단까지의 인덱스(1 ≤ abs(index) ≤ top
)와 더불어
스택에 있지 않지만
C 코드에서 접근 가능한 어떤 위치를 나타내는
가상 인덱스(pseudo-index)로 이뤄진다.
레지스트리(4.5절)와
C 함수의 upvalue(4.4절)에
접근할 때 가상 인덱스를 쓴다.
명확한 변경 가능 위치가 필요한 게 아니라 값이 필요할 뿐인 함수(예를 들면 질의 함수)는 허용 인덱스로 호출할 수 있다. 허용 인덱스는 어떤 유효 인덱스일 수도 있고 스택에 할당된 공간 내의 스택 상단 너머 어떤 양수 인덱스일 수도 있다. 즉, 스택 크기까지의 인덱스다. (0은 절대 허용 인덱스가 아니다.) 따로 언급한 경우를 제외하고 API의 함수들은 허용 인덱스로 동작한다.
허용 인덱스는 스택 값 질의 시 스택 상단을 확인하는 추가 검사를 피하게 해 준다. 예를 들어 C 함수에서 세 번째 인자를 질의할 때 세 번째 인자가 있는지 여부, 즉 3이 유효 인덱스인지 여부를 확인해 볼 필요가 없다.
허용 인덱스로 호출 가능한 함수에서
유효 인덱스 아닌 위치는
가상 타입 LUA_TNONE
인 값을 담고 있는
것처럼 처리한다.
그 값은 nil 값처럼 작동한다.
C 함수를 생성할 때
어떤 값들을 연계해서
C 클로저를 만들 수 있다.
(lua_pushcclosure
참고.)
그 값들을 upvalue라고 하며
호출된 함수에서 언제나 접근 가능하다.
C 함수 호출 시
그 upvalue들은 언제나 특정 가상 인덱스에 위치하게 된다.
매크로 lua_upvalueindex
가
그 가상 인덱스를 만들어 준다.
함수에 연계된 첫 번째 upvalue가
lua_upvalueindex(1)
에 있는 식이다.
현재 함수의 upvalue 개수보다 큰
(하지만 클로저 upvalue 최대 개수에 1을 더한 값인 256보다는 크지 않은)
n으로 lua_upvalueindex(n)
에 접근하면
허용이지만 유효하지 않은 인덱스가 나온다.
루아에는 레지스트리라는
미리 정의된 테이블이 있다.
C 코드에서 이 테이블에
어떤 루아 값이든 저장할 수 있다.
레지스트리 테이블은 항상 가상 인덱스
LUA_REGISTRYINDEX
에 위치한다.
어느 C 라이브러리에서든 이 테이블에 값을 저장할 수 있되,
충돌을 피하기 위해
다른 라이브러리들과 다른 키를
고르도록 신경을 써야 한다.
보통 라이브러리 이름을 담은 문자열이나
코드 내 C 객체의 주소인 light userdata,
또는 코드에서 생성한 루아 객체를 키로 쓰면 된다.
변수 이름에서처럼
밑줄로 시작하고 이어서 대문자 글자들이 오는 문자열 키는
루아 자체 용도로 예약되어 있다.
레지스트리 내의 정수 키는
참조 메커니즘(luaL_ref
)과
몇 가지 사전 정의 값들에 쓰인다.
따라서 다른 용도로 정수 키를 사용해서는 안 된다.
루아 상태를 새로 생성하면
그 레지스트리에는 몇 가지 미리 정의된 값들이 있다.
그 사전 정의 값들의 인덱스는
lua.h
에 상수로 정의되어 있는 정수 키다.
다음 상수가 정의되어 있다.
LUA_RIDX_MAINTHREAD
:
레지스트리의 이 인덱스에는
상태의 주 스레드가 있다.
(주 스레드는 상태와 함께 생성된 스레드다.)
LUA_RIDX_GLOBALS
:
레지스트리의 이 인덱스에는
전역 환경이 있다.
내부적으로 루아는 C의 longjmp
기능을 이용해 오류를 처리한다.
(루아를 C++로 컴파일하면 예외를 이용한다.
소스 코드에서 LUAI_THROW
로 검색하면 자세한 내용이 나온다.)
루아에서 (메모리 할당 오류나 타입 오류 같은) 오류를 만나면
오류를 던진다.
즉, 긴 점프를 한다.
보호 환경에서는 setjmp
를 사용해
복원 지점을 지정한다.
그러면 오류 발생 시 가장 최근의 활성 복원 지점으로 점프한다.
C 함수 내에서 lua_error
를 호출해서 오류를 던질 수 있다.
API의 함수 대부분이 이를테면 메모리 할당 오류 때문에 오류를 던질 수 있다. 각 함수별 설명에 오류를 던질 수 있는지 여부가 나와 있다.
보호 환경 밖에서 오류가 생기면
루아에서 패닉 함수를 호출하고서
(lua_atpanic
참고)
abort
를 호출해서 호스트 응용을 끝낸다.
끝내는 것을 막으려면 패닉 함수에서
(이를테면 루아 밖의 자체 복원 지점으로 긴 점프를 해서)
절대 반환하지 않으면 된다.
이름에서 알 수 있듯
패닉 함수는
최후의 수단이다.
따라서 가급적 쓰지 않는 게 좋다.
일반적으로
루아에서 루아 상태를 가지고 C 함수를 호출할 때는
이미 보호 상태일 것이기에
C 함수에서 그 루아 상태에 무엇이든 할 수 있다.
하지만 C 코드에서 다른 루아 상태에
(예를 들어 그 함수의 루아 인자,
레지스트리에 저장된 루아 상태,
lua_newthread
의 결과에)
작업을 하는 경우에는
오류를 던질 수 없는 API 호출에만
그 상태를 써야 한다.
패닉 함수는 메시지 핸들러인 것처럼 돈다. (2.3절 참고.) 특별히 스택 상단에 오류 객체가 있다. 하지만 스택 공간에 대해선 어떤 보장도 없다. 패닉 함수에서 스택에 뭔가를 집어넣으려면 먼저 가용 공간을 확인해야 한다. (4.2절 참고.)
코루틴 양보에 루아 내부적으로 C의 longjmp
기능을 이용한다.
그래서 C 함수 foo
에서 어떤 API 함수를 호출했는데
그 API 함수에서
(직접적으로, 또는 양보하는 다른 함수를 호출해서 간접적으로)
양보하면 더 이상 루아에서 foo
로 반환할 수 없다.
longjmp
때문에 C 스택에서 프레임이 없어지기 때문이다.
이런 문제를 피하기 위해
API 호출을 거쳐서 양보하려고 할 때는 루아에서 항상 오류를 던진다.
단, 세 함수 lua_yieldk
, lua_callk
, lua_pcallk
가 예외인데,
이 함수들은 양보 후 실행을 이어 갈
속행 함수를 (k
라는 매개변수로) 받는다.
속행을 설명하기 위해 용어를 좀 정하겠다.
루아에서 호출하는 C 함수가 있고,
이를 시작 함수라고 할 것이다.
이 시작 함수가 C API의 그 세 함수 중 하나를 호출하는데,
이를 피호출 함수라고 할 것이다.
그 피호출 함수에서 현재 스레드를 양보한다.
(피호출 함수가 lua_yieldk
일 때,
또는 피호출 함수가 lua_callk
나 lua_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_pcall
을 lua_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_yieldk
및 lua_callk
인 경우에는
루아에서 속행 함수를 호출할 때 상태가 항상 LUA_YIELD
다.
(이 두 함수에서는
오류 경우에 루아에서 속행 함수를 호출하지 않는다.
오류 처리를 하는 함수가 아니기 때문이다.)
비슷한 방식으로 lua_callk
사용 시에는
LUA_OK
를 상태로 해서
속행 함수를 호출해야 할 것이다.
(lua_yieldk
인 경우에는
속행 함수를 직접 호출하는 것이 별 의미가 없다.
보통 lua_yieldk
가 반환하지 않기 때문이다.)
루아는 속행 함수를 시작 함수인 것처럼 다룬다.
속행 함수가 시작 함수와 같은 루아 스택을 받으며,
그 스택은 피호출 함수가 반환했을 때와 같은 상태다.
(예를 들어
lua_callk
후에
스택에서 함수와 인자들이 제거되고 호출 결과로 교체된다.)
또한 upvalue들이 같다.
그리고 무엇을 반환하든 루아에서 이를
시작 함수의 반환처럼 처리한다.
C API의 모든 함수와 타입을 알파벳 순서로 나열한다. 각 함수에는 이 문단 오른편과 같은 표시가 있다. [-o, +p, x]
첫 번째 필드 o
는
함수가 스택에서 항목을 몇 개나 꺼내는가이다.
두 번째 필드 p
는
함수가 스택에 항목을 몇 개나 집어넣는가이다.
(어떤 함수든 항상 인자를 꺼낸 뒤에 결과를 집어넣는다.)
x|y
형태인 필드는 함수가 상황에 따라
x
개 또는 y
개 항목을
집어넣을 (꺼낼) 수 있다는 뜻이다.
물음표 '?
'는
인자만 봐서는 함수가 몇 개 항목을
꺼내는지/집어넣는지 알 수 없다는 뜻이다.
(이를테면 스택 내용에 따라 달라질 수 있다.)
세 번째 필드 x
는
함수가 오류를 던질 수 있는지를 알려 준다.
'-
'는 함수가 절대 오류를 던지지 않는다는 뜻이다.
'm
'은 함수가 메모리 부족 오류나
__gc
메타메소드 실행 중의 오류를 던질 수 있다는 뜻이다.
'e
'는 함수가 어떤 오류도 던질 수 있다는
(직접 또는 메타메소드를 통해 임의의 루아 코드를 실행할 수 있다는)
뜻이다.
'v
'는 함수가 의도적으로 오류를 던질 수 있다는 뜻이다.
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
다.
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
을 반환한다.
루아에서는 osize >= nsize
일 때
할당자가 절대 실패하지 않는다고 가정한다.
다음은 간단한 할당자 함수 구현이다.
보조 라이브러리의 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에서 보장한다.
위 코드에서는 블록을 줄일 때 realloc
이 실패하지 않는다고 가정한다.
(표준 C에서 이런 동작을 보장하지는 않지만 안전한 가정인 것 같다.)
lua_arith
[-(2|1), +1, e]
void lua_arith (lua_State *L, int op);
스택 상단에 있는 두 값에 대해 (반수나 NOT은 한 값에 대해) 산술 연산이나 비트 연산을 수행한다. 상단 쪽 값을 두 번째 피연산자로 하며, 값들을 꺼내고 연산 결과를 집어넣는다. 대응하는 루아 연산자의 처리 방식을 따른다. (즉 메타메소드를 호출할 수도 있다.)
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.6절 참고.)
lua_call
[-(nargs+1), +nresults, e]
void lua_call (lua_State *L, int nargs, int nresults);
함수를 호출한다.
함수를 호출하려면 규약을 따라야 한다.
먼저 호출할 함수를 스택에 집어넣는다.
다음으로 함수 인자들을 정순서로 집어넣는다.
즉, 첫 번째 인자를 첫 번째로 집어넣는다.
마지막으로 lua_call
을 호출한다.
nargs
는 스택에 집어넣은 인자 개수다.
함수가 호출될 때
인자와 함수 값 모두가 스택에서 빠진다.
그리고 함수가 반환할 때 함수 결과가 스택에 들어간다.
그 결과가 nresults
개로 조정된다.
단, nresults
가 LUA_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.7절 참고.)
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 함수 타입.
C 함수에서 루아와 올바로 의사소통하려면
매개변수 및 결과 전달 방식을 규정하는
규약을 따라야 한다.
C 함수가 루아로부터 인자를 받을 때는
스택에서 정순서로 (첫 번째 인자를 첫 번째로 집어넣기) 받는다.
그래서 함수 시작에서
lua_gettop(L)
을 호출하면 함수가 받은 인자 개수를 반환한다.
첫 번째 인자가 (있다면) 1번 인덱스에 있고
마지막 인자가 lua_gettop(L)
인덱스에 있다.
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, m]
int lua_gc (lua_State *L, int what, int data);
쓰레기 수집기를 제어한다.
이 함수는 매개변수 what
의 값에 따라
여러 가지 작업을 수행한다.
LUA_GCSTOP
:
쓰레기 수집기를 멈춘다.
LUA_GCRESTART
:
쓰레기 수집기를 다시 시작한다.
LUA_GCCOLLECT
:
쓰레기 수집 주기 한 번을 수행한다.
LUA_GCCOUNT
:
루아에서 현재 사용 중인 메모리의 (kB 단위) 양을 반환한다.
LUA_GCCOUNTB
:
루아에서 현재 사용 중인 메모리의 바이트 양을 1024로 나눈 나머지를 반환한다.
LUA_GCSTEP
:
쓰레기 수집의 점진 단계 한 번을 수행한다.
LUA_GCSETPAUSE
:
data
를 수집기의 휴지 시간(2.5절)
새 값으로 설정하고
이전 휴지 시간 값을 반환한다.
LUA_GCSETSTEPMUL
:
data
를 수집기의 단계 비율(2.5절)
새 값으로 설정하고
이전 단계 비율 값을 반환한다.
LUA_GCISRUNNING
:
수집기가 동작 중인지 (즉 중단되지 않았는지를) 알려 주는 불리언을 반환한다.
이 옵션들에 대한 더 자세한 내용은
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]
를 스택에 집어넣는다.
여기서 t
는 지정한 인덱스에 있는 값이다.
루아 내에서처럼 이 함수가 "index" 이벤트에 대한
메타메소드를 유발할 수 있다.
(2.4절 참고.)
집어넣은 값의 타입을 반환한다.
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
의 값을 스택에 집어넣는다.
그 값의 타입을 반환한다.
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_getuservalue
[-0, +1, –]
int lua_getuservalue (lua_State *L, int index);
지정한 인덱스에 있는 full userdata에 연계된 루아 값을 스택에 집어넣는다.
집어넣은 값의 타입을 반환한다.
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);
지정한 인덱스에 있는 값이 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.7절 참고.)
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
의 반환 값은 다음과 같다.
LUA_OK
: 오류 없음LUA_ERRSYNTAX
:
사전 컴파일 중 구문 오류LUA_ERRMEM
:
메모리 할당 오류 (메모리 부족)LUA_ERRGCMM
:
__gc
메타메소드 실행 중 오류.
(이 오류는 적재하려는 청크와 아무 관련이 없다.
쓰레기 수집기가 만들어 내는 오류이다.)
lua_load
함수는 사용자가 제공한 reader
함수를 사용해
청크를 읽어 들인다. (lua_Reader
참고.)
data
인자는 읽기 함수에게 전달하는 불투명한 값이다.
chunkname
인자는 청크에 이름을 준다.
오류 메시지와 디버그 정보(4.9절)에 쓰인다.
청크가 텍스트인지 바이너리인지 lua_load
에서 자동으로 탐지해서
그에 맞게 적재한다. (luac
프로그램 참고.)
문자열 mode
는 load
함수에서처럼 동작하며,
추가로 NULL
값이 문자열 "bt
"와 동등하다.
lua_load
내부적으로 스택을 사용한다.
따라서 읽기 함수에서 반환할 때는 항상
스택이 변경 없는 상태여야 한다.
결과 함수에 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_newuserdata
[-0, +1, m]
void *lua_newuserdata (lua_State *L, size_t size);
이 함수는 지정한 크기의 메모리 블록을 새로 할당해서 그 블록 주소의 새 full userdata를 스택에 집어넣고 그 주소를 반환한다. 호스트 프로그램에서 그 메모리를 마음대로 사용할 수 있다.
lua_next
[-1, +(2|0), e]
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
호출에
혼란을 줄 수 있다.
순회 중 테이블을 변경하는 것에 대한 주의 사항은
함수 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
이 오류를 잡아서
스택에 값 하나(오류 객체)를 집어넣고
오류 코드를 반환한다.
lua_call
과 마찬가지로
lua_pcall
은 항상
함수와 그 인자들을 스택에서 제거한다.
msgh
가 0이면
스택으로 반환된 오류 객체가
정확히 원래의 오류 객체다.
그렇지 않으면 msgh
는
메시지 핸들러의 스택 인덱스다.
(이 인덱스는 가상 인덱스일 수 없다.)
런타임 오류 발생 시
오류 객체로 그 함수가 호출되며
그 반환 값이
lua_pcall
이
스택으로 반환하는 객체가 된다.
보통은 오류 객체에 스택 트레이스백 같은 디버그 정보를 추가하는 데
메시지 핸들러를 쓴다.
lua_pcall
반환 후에는
스택이 이미 풀렸으므로
그런 정보를 수집할 수 없다.
lua_pcall
함수는
(lua.h
에 정의된) 다음 상수들 중 하나를 반환한다.
LUA_OK
(0):
성공.LUA_ERRRUN
:
런타임 오류.
LUA_ERRMEM
:
메모리 할당 오류.
이 오류에 대해선 루아가 메시지 핸들러를 호출하지 않는다.
LUA_ERRERR
:
메시지 핸들러 동작 중 오류.
LUA_ERRGCMM
:
__gc
메타메소드 동작 중 오류.
이 오류에 대해선 루아가 메시지 핸들러를 호출하지 않는다.
(이런 류의 오류는 일반적으로
호출하려는 함수와 아무 관련이 없기 때문이다.)
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.7절 참고.)
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 클로저를 만드는 것이 가능하다.
(4.4절 참고.)
그러면 호출 시 그 함수에서 값들에 접근할 수 있다.
C 함수에 값을 연계하려면
먼저 값을 스택에 집어넣어야 한다.
(값이 여러 개일 때는 첫 번째 값을 첫 번째로 집어넣는다.)
그리고 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 함수를 스택에 집어넣는다.
이 함수는 C 함수 포인터를 받아서
함수
타입 루아 값을 스택에 집어넣는다.
그 값을 호출하면 대응하는 C 함수가 불린다.
루아에서 호출 가능해야 하는 함수는 모두
정확한 규약에 따라 매개변수를 받고
결과를 반환해야 한다.
(lua_CFunction
참고.)
lua_pushfstring
[-0, +1, e]
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
서식을 준 문자열을 스택에 집어넣고
그 문자열에 대한 포인터를 반환한다.
ISO C 함수 sprintf
와 비슷하지만
몇 가지 중요한 차이가 있다.
%%
' (문자 '%
' 삽입),
'%s
' (영 종료 문자열 삽입, 크기 제약 없음),
'%f
' (lua_Number
삽입),
'%I
' (lua_Integer
삽입),
'%p
' (포인터를 16진수로 삽입),
'%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 userdata는 void*
포인터를 나타낸다.
(수와 마찬가지로) 하나의 값이다.
따로 생성하지 않고,
개별 메타테이블이 없으며,
(생성된 적이 없으므로) 수집되지 않는다.
한 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
에 있는 메모리를 해제하거나 재사용할 수 있다.
문자열의 내부 사본에 대한 포인터를 반환한다.
s
가 NULL
이면 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, m]
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);
인덱스 index1
과 index2
의 두 값이
단순 비교로 (즉 __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, –]
size_t 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_resume
[-?, +?, –]
int lua_resume (lua_State *L, lua_State *from, int nargs);
지정한 스레드 L
에서 코루틴을 시작하고 재개한다.
코루틴을 시작하려면
메인 함수와 인자를 스레드 스택에 집어넣고서
nargs
를 인자 개수로 해서
lua_resume
을 호출하면 된다.
코루틴이 실행을 중지하거나 완료할 때 이 호출이 반환한다.
반환 시 lua_yield
에 준 모든 값이,
또는 몸체 함수에서 반환한 모든 값이 스택에 들어 있다.
코루틴이 양보한 경우 lua_resume
이
LUA_YIELD
를 반환하고,
코루틴이 오류 없이 실행을 마친 경우 LUA_OK
를 반환하고,
오류가 발생한 경우 오류 코드(lua_pcall
)를 반환한다.
오류가 발생한 경우 스택이 풀려 있지 않으므로 디버그 API를 사용할 수 있다. 스택 상단에 오류 객체가 있다.
코루틴을 재개하려면
최근 lua_yield
의 결과가 있으면 제거하고
yield
의 결과로 전달할 값들만 스택에 둔 다음
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);
지정한 상태의 할당자 함수를 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_setmetatable
[-1, +0, –]
void lua_setmetatable (lua_State *L, int index);
스택에서 테이블을 꺼내서 지정한 인덱스에 있는 값의 새 메타테이블로 설정한다.
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_setuservalue
[-1, +0, –]
void lua_setuservalue (lua_State *L, int index);
스택에서 값을 꺼내서 지정한 인덱스에 있는 full userdata에 연계된 새 값으로 설정한다.
lua_State
typedef struct lua_State lua_State;
스레드를, 그리고 (그 스레드를 통해) 간접적으로 루아 인터프리터의 전체 상태를 가리키는 불투명한 자료 구조. 루아 라이브러리는 완전하게 재진입 가능하다. 즉, 전역 변수가 전혀 없다. 이 자료 구조를 통해 상태에 대한 모든 정보에 접근할 수 있다.
라이브러리의 모든 함수에 첫 번째 인자로 이 구조체에 대한 포인터를 주어야 한다.
단, 무에서부터 루아 상태를 만드는
lua_newstate
는 예외다.
lua_status
[-0, +0, –]
int lua_status (lua_State *L);
스레드 L
의 상태를 반환한다.
정상 스레드면 상태가 0(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);
영 종료 문자열 s
를 수로 변환하고,
그 수를 스택에 집어넣고,
문자열의 총 크기, 즉 길이 더하기 1을 반환한다.
변환 결과는 루아 어휘 규정에 따라
정수나 실수가 될 수 있다.
(3.1절 참고.)
문자열에 전후 공백과 부호가 있을 수 있다.
문자열이 유효한 수가 아니면
0을 반환하며 아무것도 집어넣지 않는다.
(따라서 결과를 불리언으로 쓸 수도 있다.
변환이 성공하면 참이다.)
lua_toboolean
[-0, +0, –]
int lua_toboolean (lua_State *L, int index);
지정한 인덱스에 있는 루아 값을 C 불리언 값(0 또는 1)으로 변환한다.
루아의 여느 검사와 마찬가지로
false와 nil을 제외한 모든 루아 값에 대해
lua_toboolean
이 참을 반환하고
둘 중 하나면 거짓을 반환한다.
(진짜 불리언인 값만 받아들이고 싶다면
lua_isboolean
으로 값의 타입을 확인하면 된다.)
lua_tocfunction
[-0, +0, –]
lua_CFunction lua_tocfunction (lua_State *L, int index);
지정한 인덱스에 있는 값을 C 함수로 변환한다.
그 값이 C 함수여야 한다.
아니면 NULL
을 반환한다.
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
은
루아 상태 내 문자열에 대한 포인터를 반환한다.
이 문자열에는 (C에서처럼) 항상 마지막 문자 뒤에
0('\0
')이 있다.
하지만 내용 중간에도 다른 0이 있을 수 있다.
루아에 쓰레기 수집기가 있기 때문에
lua_tolstring
이 반환한 포인터가
해당 루아 값이 스택에서 제거된 후에 유효하리라는 보장이 없다.
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*
)로 변환한다.
그 값은 userdata, 테이블, 스레드, 함수일 수 있다.
아니면 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);
지정한 인덱스에 있는 값이 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
(0),
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.4절 참고.)
lua_version
[-0, +0, –]
const lua_Number *lua_version (lua_State *L);
루아 코어에 (C 정적 변수로) 저장되어 있는
버전 번호의 주소를 반환한다.
유효한 lua_State
로 호출 시
그 상태를 생성하는 데 사용한 버전의 주소를 반환한다.
NULL
로 호출 시
그 호출을 실행하는 버전의 주소를 반환한다.
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
에 준
data
매개변수를 전달한다.
쓰기 함수는 오류 코드를 반환한다.
0은 오류 없음을 뜻한다.
다른 값은 오류를 뜻하며 lua_dump
가 더는 쓰기 함수를 호출하지 않게 한다.
lua_xmove
[-?, +?, –]
void lua_xmove (lua_State *from, lua_State *to, int n);
한 상태의 스레드들 간에 값을 교환한다.
이 함수는 스택 from
에서 값을 n
개 꺼내서
스택 to
에 집어넣는다.
lua_yield
[-?, +?, e]
int lua_yield (lua_State *L, int nresults);
이 함수는 lua_yieldk
와 동등하되
속행이 없다. (4.7절 참고.)
그래서 스레드가 실행을 재개할 때,
lua_yield
호출 함수를 호출했던 함수에서
실행을 이어 간다.
lua_yieldk
[-?, +?, e]
int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k);
코루틴(스레드)을 양보한다.
C 함수에서 lua_yieldk
를 호출하면
동작 중인 코루틴이 실행을 중지하며
그 코루틴을 시작했던 lua_resume
호출이 반환한다.
매개변수 nresults
는
lua_resume
에게 결과로 전달할 스택의 값 개수다.
코루틴이 다시 실행을 재개할 때
지정한 속행 함수 k
를 루아에서 호출해서
양보를 한 C 함수의 실행을 이어 간다.
(4.7절 참고.)
그 속행 함수가 받는 스택은 이전 함수의 스택에서
nresults
개 결과가 없어지고
lua_resume
이 받은 인자로 교체된 것이다.
또한
lua_yieldk
에 준
ctx
값을 속행 함수가 받는다.
일반적으로 이 함수는 반환하지 않는다.
나중에 코루틴이 실행을 재개할 때
속행 함수로 실행이 이어지기 때문이다.
하지만 한 가지 특별한 경우가 있는데,
행 훅이나 카운트 훅(4.9절) 안에서
이 함수를 호출할 때다.
그 경우 속행 없이
(아마도 lua_yield
형태로),
그리고 결과도 없이 lua_yieldk
를 호출해야 하며
호출 바로 다음에서 훅이 반환해야 한다.
그러면 루아에서 양보를 하고,
다시 코루틴이 실행을 재개할 때
훅을 유발했던 (루아) 함수의 실행을 정상적으로 이어 가게 된다.
속행 함수 없는 미처리 C 호출이 있는 스레드에서 호출하거나 재개에 의해 동작 중이 아닌 스레드(가령 메인 스레드)에서 호출하는 경우 이 함수가 오류를 던질 수 있다.
루아에는 어떤 디버깅 장치도 내장되어 있지 않다. 대신 함수와 훅을 통해서 특별한 인터페이스를 제공한다. 이 인터페이스를 이용해 인터프리터의 "내부 정보"가 필요한 다양한 디버거나 프로파일러, 기타 도구들을 만들 수 있다.
lua_Debug
typedef struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) */ const char *what; /* (S) */ const char *source; /* (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) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ 기타 필드 } lua_Debug;
함수나 활성 레코드에 대한 여러 정보를 담는 데 쓰는 구조체.
lua_getstack
에서 이후 사용을 위해
이 구조체의 비공개 부분만을 채운다.
lua_Debug의 다른 필드들에
유용한 정보를 채우려면
lua_getinfo
를 호출하면 된다.
lua_Debug
의 필드들의 의미는 다음과 같다.
source
:
함수를 만든 청크의 이름.
source
가 '@
'로 시작하면
함수가 파일에 정의되어 있었다는 뜻이고
'@
' 다음이 그 파일의 이름이다.
source
가 '=
'로 시작하면
나머지 내용이 어떤 사용처별 방식으로 출처를 기술하는 것이다.
그 외 경우는
함수가 문자열로 정의되었다는 뜻이고
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
:
함수의 upvalue 개수.
nparams
:
함수의 고정 매개변수 개수.
(C 함수에는 항상 0.)
isvararg
:
함수가 가변 인자 함수면 참이다.
(C 함수에는 항상 참.)
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), e]
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
구조체에서 채울 필드나
스택에 집어넣을 값을 선택한다.
n
': name
및 namewhat
필드를 채운다.
S
':
source
, short_src
, linedefined
,
lastlinedefined
, what
필드를 채운다.
l
': currentline
필드를 채운다.
t
': istailcall
필드를 채운다.
u
': nups
,
nparams
, isvararg
필드를 채운다.
f
':
해당 단계에서 실행 중인 함수를
스택에 집어넣는다.
L
':
그 함수 상의 유효 행의 번호가 인덱스인 테이블을
스택에 집어넣는다.
(유효 행이란 어떤 연관 코드가 있는 행이다.
즉, 중단점을 넣을 수 있는 행이다.
유효하지 않은 행으로는 빈 행과 주석 등이 있다.)
이 옵션을 'f
' 옵션과 함께 주면
함수 다음에 테이블을 집어넣는다.
오류 시 (예를 들어 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
은 변수의 값을 스택에 집어넣고
그 이름을 반환한다.
두 번째 경우에는
ar
이 NULL
이어야 하고
조사할 함수가 스택 상단에 있어야 한다.
이 경우 (어느 변수가 활성인지에 대한 정보가 없으므로)
루아 함수의 매개변수들만 보이며
스택에는 아무 값도 집어넣지 않는다.
인덱스가 활성 지역 변수 개수보다 크면
NULL
을 반환한다.
(그리고 아무것도 집어넣지 않는다.)
lua_getstack
[-0, +0, –]
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
인터프리터 런타임 스택에 대한 정보를 얻는다.
이 함수는 해당 단계에서 실행 중인
함수 활성 레코드의 식별 정보를
lua_Debug
의 해당 부분에 채운다.
0번 단계가 현재 돌고 있는 함수고
n+1 번 단계는 n 번 단계를 호출한 함수다.
(꼬리 호출은 스택에서 자리를 차지하지 않으므로 제외된다.)
오류가 없을 때 lua_getstack
은 1을 반환한다.
스택 깊이보다 큰 단계 값으로 호출하면 0을 반환한다.
lua_getupvalue
[-0, +(0|1), –]
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
인덱스 funcindex
에 있는 클로저의
n
번째 upvalue에 대한 정보를 얻는다.
그 upvalue의 값을 스택에 집어넣고
이름을 반환한다.
인덱스 n
이 upvalue 개수보다 크면
NULL
을 반환한다.
(그리고 아무것도 집어넣지 않는다.)
C 함수의 경우 이 함수는 모든 upvalue에
이름으로 빈 문자열 ""
을 쓴다.
(루아 함수의 경우
upvalue는 함수에서 사용하여 그 결과로 클로저에 포함된
외부의 지역 변수다.)
upvalue들은 함수 전체에서 활성이므로 특별한 순서가 없다. 임의 순서로 번호가 붙는다.
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
일 수도 있다.
꼬리 호출인 경우에는 대응하는 반환 이벤트가 없다.
훅을 실행하는 동안 루아에서는 다른 훅 호출을 꺼 둔다. 그래서 훅에서 루아를 다시 호출해서 함수나 청크를 실행하는 경우 훅 호출 없이 실행이 이뤄진다.
훅 함수에는 속행이 있을 수 없다.
즉, 널이 아닌 k
로 lua_yieldk
,
lua_pcallk
, lua_callk
를 호출할 수 없다.
훅 함수는 정해진 조건 하에서만 양보를 할 수 있는데,
일단 카운트 이벤트와 행 이벤트에서만 양보할 수 있다.
양보를 하려면 훅 함수에서
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
가
들어 있을 때만 의미가 있다.
각 이벤트에 대해 아래 설명처럼 훅이 호출된다.
count
개
실행한 다음마다 불린다.
(루아 함수 실행 중에만 이 이벤트가 발생한다.)
mask
를 0으로 설정하면 훅을 끈다.
lua_setlocal
[-(0|1), +0, –]
const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
해당 활성 레코드의 지역 변수의 값을 설정한다. 스택 상단의 값을 변수에 할당하고 그 이름을 반환한다. 또한 그 값을 스택에서 꺼낸다.
인덱스가 활성 지역 변수 개수보다 크면
NULL
을 반환한다.
(그리고 아무것도 꺼내지 않는다.)
매개변수 ar
과 n
은 lua_getlocal
함수에서와 같다.
lua_setupvalue
[-(0|1), +0, –]
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
클로저의 upvalue의 값을 설정한다. 스택 상단의 값을 upvalue에 할당하고 그 이름을 반환한다. 또한 그 값을 스택에서 꺼낸다.
인덱스 n
이 upvalue 개수보다 크면
NULL
을 반환한다.
(그리고 아무것도 꺼내지 않는다.)
매개변수 funcindex
와 n
은 lua_getupvalue
함수에서와 같다.
lua_upvalueid
[-0, +0, –]
void *lua_upvalueid (lua_State *L, int funcindex, int n);
인덱스 funcindex
에 있는 클로저에서
n
번째 upvalue의 고유 식별자를 반환한다.
이 고유 식별자를 이용하면 upvalue를 여러 클로저에서 공유하는지 여부를 프로그램에서 확인할 수 있다. upvalue를 공유하는 (즉 같은 외부 지역 변수에 접근하는) 루아 클로저들은 각각의 upvalue 인덱스에 대해 동일한 ID를 반환하게 된다.
매개변수 funcindex
와 n
은 lua_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를
가리키게 만든다.
보조 라이브러리에는 C와 루아를 연결해 주는 여러 편의 함수들이 있다. 기본 API가 C와 루아 사이의 모든 상호작용을 위한 기반 함수를 제공한다면 보조 라이브러리는 몇 가지 흔한 작업을 위한 상위 함수를 제공한다.
보조 라이브러리의 모든 함수와 타입은
헤더 파일 lauxlib.h
에 정의되어 있으며
앞에 luaL_
이 붙어 있다.
보조 라이브러리의 모든 함수는 기본 API를 바탕으로 만들어진 것이고, 그래서 그 API가 할 수 없는 것을 해 주지는 못한다. 그렇지만 보조 라이브러리 사용은 코드의 무모순성을 강화해 준다.
보조 라이브러리의 여러 함수에서는 내부적으로 스택 슬롯 몇 개를 추가로 쓴다. 보조 라이브러리 함수에서 슬롯을 다섯 개 미만으로 쓸 때는 스택 크기를 확인하지 않는다. 즉, 슬롯이 충분히 있다고 그냥 가정한다.
보조 라이브러리의 여러 함수들은
C 함수 인자를 검사하는 데 쓰인다.
오류 메시지가 인자에 맞춰져 있으므로
(예: "bad argument #1
")
다른 스택 값에는 이 함수를 쓰지 말아야 한다.
이름이 luaL_check*
인 함수들은
검사가 통과 안 되면 항상 오류를 던진다.
보조 라이브러리의 모든 함수와 타입을 알파벳 순서로 나열한다.
luaL_addchar
[-?, +?, m]
void luaL_addchar (luaL_Buffer *B, char c);
바이트 c
를
버퍼 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_Buffer
참고.)
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_Buffer
typedef struct luaL_Buffer luaL_Buffer;
문자열 버퍼 타입.
문자열 버퍼를 이용해 C 코드에서 루아 문자열을 조금씩 만들어 갈 수 있다. 사용 패턴은 다음과 같다.
luaL_Buffer
타입 변수 b
를 선언한다.luaL_buffinit(L, &b)
호출로 초기화한다.luaL_add*
함수를 호출해서
버퍼에 문자열 조각들을 추가한다.
luaL_pushresult(&b)
호출로 마무리한다.
그러면 스택 상단에 최종 문자열이 남는다.
결과 문자열의 총 크기를 미리 알고 있다면 다음과 같이 버퍼를 사용할 수 있다.
luaL_Buffer
타입 변수 b
를 선언한다.luaL_buffinitsize(L, &b, sz)
호출로 초기화해서
sz
크기의 공간을 미리 할당한다.luaL_pushresultsize(&b, sz)
호출로 마무리한다.
sz
는 그 공간으로 복사한 결과 문자열의 총 크기다.
정상 동작 중에
문자열 버퍼에서 쓰는 스택 슬롯 수가 바뀔 수도 있다.
따라서 버퍼 사용 중에는 스택 상단이 어디인지
알고 있다고 가정할 수 없다.
두 버퍼 동작 호출 사이에서 스택을 사용하려면
사용 방식이 평형이어야 가능하다.
즉, 어떤 버퍼 동작을 호출했을 때의 스택이
이전 버퍼 동작 직후와
같은 높이여야 한다.
(이 규칙의 유일한 예외가 luaL_addvalue
다.)
luaL_pushresult
를 호출하면
스택이 버퍼를 초기화했던 때의 높이로 돌아가고
거기에 최종 문자열이 더해진다.
luaL_buffinit
[-0, +0, –]
void luaL_buffinit (lua_State *L, 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_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
번째 함수 인자가 정수인지
(또는 정수로 변환할 수 있는지) 확인하고
그 정수를 lua_Integer
로 변환해서 반환한다.
luaL_checklstring
[-0, +0, v]
const char *luaL_checklstring (lua_State *L, int arg, size_t *l);
arg
번째 함수 인자가 문자열인지 확인하고
그 문자열을 반환한다.
l
이 NULL
이 아니면
*l
에 문자열 길이를 채운다.
이 함수는 lua_tolstring
을 써서 결과를 얻는다.
따라서 그 함수의 모든 변환 방식과 주의 사항이 여기에도 적용된다.
luaL_checknumber
[-0, +0, v]
lua_Number luaL_checknumber (lua_State *L, int arg);
arg
번째 함수 인자가 수인지 확인하고
그 수를 반환한다.
luaL_checkoption
[-0, +0, v]
int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]);
arg
번째 함수 인자가 문자열인지 확인하고
(NULL로 끝나는) lst
배열에서 그 문자열을 탐색한다.
배열에서 문자열을 발견한 인덱스를 반환한다.
인자가 문자열이 아니거나
그 문자열을 찾을 수 없으면 오류를 던진다.
def
가 NULL
이 아니면
인자 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, +?, e]
int luaL_dofile (lua_State *L, const char *filename);
지정한 파일을 적재해서 실행한다. 다음 매크로로 정의되어 있다.
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
아무 오류도 없으면 거짓을 반환하고 오류 발생 시 참을 반환한다.
luaL_dostring
[-0, +?, –]
int luaL_dostring (lua_State *L, const char *str);
지정한 문자열을 적재해서 실행한다. 다음 매크로로 정의되어 있다.
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
아무 오류도 없으면 거짓을 반환하고 오류 발생 시 참을 반환한다.
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);
mode
가 NULL
인 luaL_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
은 청크 이름이며
디버그 정보와 오류 메시지에 쓰인다.
문자열 mode
는 lua_load
함수에서처럼 동작한다.
luaL_loadfile
[-0, +1, m]
int luaL_loadfile (lua_State *L, const char *filename);
mode
가 NULL
인 luaL_loadfilex
와 동등하다.
luaL_loadfilex
[-0, +1, m]
int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
파일에서 루아 청크를 적재한다.
lua_load
를 사용해
이름이 filename
인 파일에 있는 청크를 적재한다.
filename
이 NULL
이면
표준 입력을 읽어서 적재한다.
파일 첫 행이 #
로 시작하면 그 행을 무시한다.
문자열 mode
는 lua_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을 반환한다.
(몇몇 오류 보고 함수에서 __name
항목을 이용한다.)
두 경우 모두에서 레지스트리에서 tname
에 연계되어 있는
최종 값을 스택에 집어넣는다.
luaL_newstate
[-0, +0, –]
lua_State *luaL_newstate (void);
새 루아 상태를 만든다.
표준 C realloc
함수 기반 할당자로
lua_newstate
를 호출하고서,
치명적 오류 시 표준 오류 출력에 오류 메시지를 찍는
패닉 함수(4.6절)를 설정한다.
새 상태를 반환한다.
메모리 할당 오류 발생 시 NULL
을 반환한다.
luaL_openlibs
[-0, +0, e]
void luaL_openlibs (lua_State *L);
지정한 상태 안에서 표준 루아 라이브러리 모두를 연다.
luaL_opt
[-0, +0, e]
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
를 반환한다.
그 외 경우에는 오류를 던진다.
l
이 NULL
이 아니면
*l
위치에 결과의 길이를 채운다.
결과가 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
번째 함수 인자가 수이면
그 수를 반환한다.
그 인자가 없거나 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_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_NOREF
는 luaL_ref
가 반환하는 어떤 참조와도 다르다고 보장된다.
luaL_Reg
typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg;
luaL_setfuncs
로
등록할 함수 배열을 위한 타입.
name
은 함수 이름이고
func
는 함수 포인터다.
luaL_Reg
의 배열은
name
과 func
가 모두 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
개 upvalue를 공유하게 해서 모든 함수를 생성한다.
그 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
는 핸들이 닫히거나 수집될 때
호출되어 스트림을 닫아 줄 루아 함수를 가리킨다.
이 함수는 파일 핸들을 유일한 인자로 받으며
(성공 시) true를, 또는
(오류 시) nil과 오류 메시지를 반환해야 한다.
루아에서 이 필드를 호출한 다음
필드 값을 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 문자열로 변환한다.
결과 문자열을 스택에 집어넣고 반환도 한다.
또한 len
이 NULL
이 아니면
*len
에 문자열 길이를 설정한다.
그 값에 메타테이블이 있고 __tostring
필드가 있으면
luaL_tolstring
에서 값을 인자로 해서 해당 메타메소드를 호출하여
호출 결과를 자기 결과로 쓴다.
luaL_traceback
[-0, +1, m]
void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level);
스택 L1
의 트레이스백을 만들어서 집어넣는다.
msg
가 NULL
이 아니면
트레이스백 앞쪽에 덧붙인다.
level
매개변수는 어느 단계에서
트레이스백을 시작할지를 나타낸다.
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
도 해제하여 다시 쓸 수 있게 한다.
ref
가 LUA_NOREF
나 LUA_REFNIL
이면
luaL_unref
가 아무것도 하지 않는다.
luaL_where
[-0, +1, m]
void luaL_where (lua_State *L, int lvl);
호출 스택 lvl
번 단계에서의 현재 제어 위치를 나타내는
문자열을 스택에 집어넣는다.
이 문자열은 보통 다음 형식이다.
청크이름:현재행:
0번 단계가 동작 중인 함수이고 1번 단계가 그 동작 중 함수를 호출한 함수인 식이다.
오류 메시지 시작 부분을 만드는 데 이 함수가 쓰인다.
표준 루아 라이브러리들은 C API를 통해 직접 구현된
유용한 함수들을 제공한다.
그 중 일부는 언어에 필수적인 서비스를 제공한다.
(예: type
, getmetatable
.)
다른 일부는 "외부" 서비스에 접근할 수 있게 해 준다. (예: I/O.)
또 다른 일부는 루아 자체로도 구현할 수 있지만
C로 구현할 만큼 상당히 유용하거나 중요한 성능상 요구가 있었던 것들이다.
(예: table.sort
.)
모든 라이브러리들은 공식 C API를 통해 구현되어 있으며 별도의 C 모듈로 제공된다. 현재 루아에는 다음 표준 라이브러리가 있다.
기본 라이브러리와 패키지 라이브러리를 제외한 다른 라이브러리들은 모든 함수를 전역 테이블의 필드나 객체의 메소드로 제공한다.
C 호스트 프로그램에서 이 라이브러리들에 접근하려면
luaL_openlibs
를 호출하면 된다.
그러면 모든 표준 라이브러리들을 연다.
또는 개별적으로 열기 위해 호스트 프로그램에서
luaL_requiref
를 사용해
luaopen_base
(기본 라이브러리),
luaopen_package
(패키지 라이브러리),
luaopen_coroutine
(코루틴 라이브러리),
luaopen_string
(문자열 라이브러리),
luaopen_utf8
(UTF8 라이브러리),
luaopen_table
(테이블 라이브러리),
luaopen_math
(수학 라이브러리),
luaopen_io
(I/O 라이브러리),
luaopen_os
(운영 체제 라이브러리),
luaopen_debug
(디버그 라이브러리)를
부를 수 있다.
lualib.h
에 이 함수들이 선언되어 있다.
기본 라이브러리는 루아 핵심 함수들을 제공한다. 응용에 이 라이브러리를 포함시키지 않는다면 그 요소들 중 일부를 대신하는 구현을 제공해야 하는지 여부를 조심스럽게 점검해 봐야 할 것이다.
assert (v [, message])
인자 v
의 값이 거짓(즉 nil이나 false)이면
error
를 호출한다.
그렇지 않으면 인자 전체를 반환한다.
오류 경우에는
message
가 오류 객체가 된다.
그 인자가 없으면 "assertion failed!
"를 쓴다.
collectgarbage ([opt [, arg]])
이 함수는 쓰레기 수집기에 대한 포괄적 인터페이스다.
첫 번째 인자 opt
에 따라서 다양한 기능을 수행한다.
collect
":
쓰레기 수집 주기 한 번을 수행한다.
기본 옵션이다.
stop
":
쓰레기 수집기의 자동 실행을 멈춘다.
다시 시작하기 전까지는
명시적으로 부를 때만 수집기가 돌게 된다.
restart
":
쓰레기 수집기의 자동 실행을 다시 시작한다.
count
":
루아에서 사용 중인 메모리의 (kB 단위) 총량을 반환한다.
값에 수소 부분이 있어서
1024로 곱하면
(오버플로우 되지 않는다면)
루아가 사용 중인 정확한 바이트 수가 나온다.
step
":
쓰레기 수집 단계를 수행한다.
단계 "크기"를 arg
로 조절한다.
값이 0이면
(쪼갤 수 없는) 기본 단계 한 번을 수행한다.
값이 0이 아니면
루아가 메모리를 그만큼 (kB 단위) 할당한 것처럼
수집기가 동작을 수행한다.
그 단계로 한 수집 주기가 끝난 경우 true를 반환한다.
setpause
":
arg
를 수집기의 휴지 시간(2.5절)
새 값으로 설정한다.
휴지 시간의 이전 값을 반환한다.
setstepmul
":
arg
를 수집기의 단계 비율(2.5절)
새 값으로 설정한다.
단계 비율의 이전 값을 반환한다.
isrunning
":
수집기가 동작 중인지 (즉 중단되지 않았는지를) 알려 주는
불리언을 반환한다.
dofile ([filename])
dofile
은 표준 입력(stdin
)의 내용을 실행한다.
청크가 반환한 모든 값을 반환한다.
오류 발생 시 dofile
은 그 오류를
호출자에게 전파한다. (즉 dofile
은 보호 모드로 돌지 않는다.)
error (message [, level])
message
를 오류 객체로 반환한다.
함수 error
는 절대 반환하지 않는다.
메시지가 문자열이면 일반적으로 error
에서
메시지 시작 부분에 오류 위치에 대한 약간의 정보를 추가한다.
level
인자는 그 오류 위치를 어떻게 얻을 수 있는지를 나타낸다.
단계가 1(기본값)이면 error
함수를 호출한 지점이
오류 위치다.
그리고 단계 2는 error
를 호출한 함수를 호출했던
위치를 나타내는 식이다.
단계를 0으로 주면 메시지에 오류 위치 정보를 추가하지 않는다.
_G
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을 반환하거나 아무 값도 반환하지 않는 것으로
청크 끝을 나타낸다.
구문 오류가 없으면 컴파일한 청크를 함수 형태로 반환한다. 그렇지 않으면 nil과 오류 메시지를 반환한다.
결과 함수에 upvalue가 있는 경우에
env
매개변수가 있으면 그 값을,
아니면 전역 환경의 값을
첫 번째 upvalue에 설정한다.
다른 upvalue들은 nil로 초기화한다.
(메인 청크를 적재할 때는
결과 함수에 항상 정확히 한 개의 upvalue,
즉 _ENV
변수가 있게 된다. (2.2절 참고.)
하지만 함수로부터 만든 바이너리 청크를 적재할 때는
(string.dump
참고)
결과 함수에 임의 개수의 upvalue가 있을 수 있다.)
모든 upvalue는 새것이다.
즉 다른 함수와 공유하지 않는다.
chunkname
은 오류 메시지와 디버그 정보(4.9절)에서
청크 이름으로 쓴다.
없을 때는
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
의 동작 방식이 규정되어 있지 않다.
하지만 기존 필드를 변경하는 건 괜찮다.
특히 기존 필드들을 모두 비울 수도 있다.
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
이
첫 번째 결과 뒤에 붙여서 반환한다.
오류 발생 시에는 pcall
이 false와 오류 메시지를 반환한다.
print (···)
tostring
함수로 각 인자를 문자열로 변환해서
그 값들을 stdout
으로 찍는다.
print
는 서식 출력을 위한 것이 아니다.
디버깅 등을 위해
간단히 값을 표시하는 방법일 뿐이다.
출력을 완전히 제어하려면
string.format
과 io.write
를 쓰면 된다.
rawequal (v1, v2)
__eq
메타메소드 호출 없이
v1
이 v2
와 같은지 확인한다.
불리언을 반환한다.
rawget (table, index)
__index
메타메소드 호출 없이
table[index]
의 진짜 값을 얻는다.
table
은 테이블이어야 하며
index
는 아무 값이나 가능하다.
rawlen (v)
__len
메타메소드 호출 없이
객체 v
의 길이를 반환한다.
v
는 테이블이나 문자열이어야 한다.
정수를 반환한다.
rawset (table, index, value)
__newindex
메타메소드 호출 없이
table[index]
의 진짜 값을 value
로 설정한다.
table
은 테이블이어야 한다.
index
는 nil과 NaN를 제외한 아무 값이나 가능하고
value
는 아무 루아 값이나 가능하다.
이 함수는 table
을 반환한다.
select (index, ···)
index
가 수이면
index
번째 인자 뒤의 모든 인자들을 반환한다.
음수는 끝부터 거꾸로 인덱스를 센다. (-1이 마지막 인자다.)
수가 아니면 index
가 문자열 "#"
이어야 하며
받은 나머지 인자들의 총개수를 반환한다.
setmetatable (table, metatable)
지정한 테이블의 메타테이블을 설정한다.
(루아 코드에서 다른 타입들의 메타테이블을 바꾸려면
디버그 라이브러리(6.10절)를 사용해야 한다.)
metatable
이 nil이면
지정한 테이블의 메타테이블을 제거한다.
원래 있던 메타테이블에 __metatable
필드가 있으면
오류를 던진다.
이 함수는 table
을 반환한다.
tonumber (e [, base])
base
없이 호출 시
tonumber
는 인자를 수로 변환하려고 시도한다.
인자가 이미 수이거나
수로 변환 가능한 문자열이면
그 수를 반환한다.
그렇지 않으면 nil을 반환한다.
문자열 변환 결과는 루아 어휘 규정에 따라 정수나 실수가 될 수 있다. (3.1절 참고.) (문자열에 전후 공백과 부호가 있을 수 있다.)
base
를 주어서 호출 시
e
는 그 진법에서
정수로 해석되는 문자열이어야 한다.
기수로 2에서 36까지 어떤 정수도 가능하다.
10을 넘는 진법에서는 (대문자 또는 소문자) 글자 'A
'가 10을 나타내고
'B
'가 11을 나타내고,
그런 식으로 'Z
'는 35를 나타낸다.
지정한 진법에서 문자열 e
가 유효한 수가 아니면
함수가 nil을 반환한다.
tostring (v)
string.format
을 쓰면 된다.)
v
의 메타테이블에 __tostring
필드가 있으면
해당 값을 v
를 인자로 해서 호출하여
호출 결과를 tostring
의 결과로 쓴다.
type (v)
nil
" (값 nil이 아니라 문자열),
"number
",
"string
",
"boolean
",
"table
",
"function
",
"thread
",
"userdata
"이다.
_VERSION
동작 중인 루아 버전을 담은 문자열을 가지고 있는
전역 변수다. (함수가 아니다.)
현재 이 변수의 값은 "Lua 5.3
"이다.
xpcall (f, msgh [, arg1, ···])
이 함수는 pcall
과 비슷하되,
새 메시지 핸들러 msgh
를 설정한다.
이 라이브러리는 코루틴을 조작하는 동작들로 이뤄져 있으며
테이블 coroutine
안에 들어 있다.
코루틴에 대한 일반적 설명은 2.6절을 보라.
coroutine.create (f)
f
를 몸체로 해서 새 코루틴을 만든다.
f
는 함수여야 한다.
"thread"
타입 객체인
새 코루틴을 반환한다.
coroutine.isyieldable ()
동작 중인 코루틴이 양보할 수 있으면 참을 반환한다.
동작 중인 코루틴이 양보할 수 있으려면 메인 스레드가 아니고 양보 불가능한 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
의 추가 결과로 전달된다.
패키지 라이브러리는 루아에서 모듈을 적재하기 위한
기본 요소들을 제공한다.
전역 환경으로 직접 내보내는 함수는
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
가 오류를 던진다.
package.config
패키지의 컴파일 시점 설정들을 기술하는 문자열. 이 문자열은 다음 행들이 차례로 이어진 것이다.
\
'이고 다른 모든 시스템에서 '/
'이다.;
'이다.?
'이다.!
'이다.luaopen_
함수 이름을 만들어 낼 때
이후 텍스트를 모두 무시하게 하는 표시다.
기본값은 '-
'이다.
package.cpath
require
에서 C 적재 함수 탐색에 쓰는 경로.
루아 경로 package.path
와 같은 방식으로
C 경로 package.cpath
를 초기화한다.
환경 변수 LUA_CPATH_5_3
이나
환경 변수 LUA_CPATH
를, 아니면
luaconf.h
에 정의된 기본 경로를 사용한다.
package.loaded
어느 모듈이 이미 적재되어 있는지를 제어하기 위해
require
에서 쓰는 테이블.
모듈 modname
을 require
했는데
package.loaded[modname]
이 거짓이 아니면
그냥 거기 저장되어 있는 값을 반환한다.
이 변수는 실제 테이블에 대한 참조일 뿐이다.
이 변수에 할당을 해도
require
에서 쓰는 테이블은 바뀌지 않는다.
package.loadlib (libname, funcname)
호스트 프로그램을 C 라이브러리 libname
과 동적으로 링크한다.
funcname
이 "*
"이면
라이브러리와 링크해서
그 라이브러리가 내보내는 심볼들을
다른 동적 링크 라이브러리에서 이용할 수 있게 만들기만 한다.
그렇지 않으면
라이브러리에서 함수 funcname
을 찾아서
C 함수 형태로 반환한다.
따라서 funcname
은 lua_CFunction
원형을 따라야 한다.
(lua_CFunction
참고.)
이 함수는 패키지 및 모듈 시스템을 완전히 건너뛰는
저수준 함수다.
require
와 달리
경로 탐색을 수행하지 않으며
자동으로 확장자를 추가하지 않는다.
libname
은 필요시 경로와 확장자까지 포함한
완전한 C 라이브러리 파일 이름이어야 한다.
funcname
은 C 라이브러리에서 내보내는 바로 그 이름이어야 한다.
(사용하는 C 컴파일러와 링커에 따라 달라질 수 있다.)
이 기능을 표준 C에서 지원하지 않는다.
그래서 일부 플랫폼에서만
(윈도우, 리눅스, 맥 OS X, 솔라리스, BSD,
기타 dlfcn
표준을 지원하는 유닉스 시스템)
사용 가능하다.
package.path
require
에서 루아 적재 함수 탐색에 쓰는 경로.
루아가 시작할 때 이 변수를
환경 변수 LUA_PATH_5_3
이나
환경 변수 LUA_PATH
의 값으로 초기화한다.
그 환경 변수들이 정의되어 있지 않으면
luaconf.h
에 정의된 기본 경로로 초기화한다.
환경 변수 값 내에 ";;
"가 있으면
기본 경로로 바뀐다.
package.preload
개별 모듈을 위한 적재 함수들을 저장하는 테이블.
(require
참고.)
이 변수는 실제 테이블에 대한 참조일 뿐이다.
이 변수에 할당을 해도
require
에서 쓰는 테이블은 바뀌지 않는다.
package.searchers
모듈을 적재하는 방식을 제어하기 위해 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
가 반환한
모듈 발견 파일 이름을 추가 값으로 반환한다.
첫 번째 탐색 함수는 추가 값을 반환하지 않는다.
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
를 차례대로
열어 보게 된다.
읽기 모드로 열 수 있는 첫 번째 파일의 치환 후 이름을 (파일을 닫고서) 반환한다. 성공한 파일이 없으면 nil과 오류 메시지를 반환한다. (그 오류 메시지에는 열기를 시도한 모든 파일 이름이 나열되어 있다.)
이 라이브러리는 부분 문자열 검색과 추출, 패턴 검사 같은 문자열 조작을 위한 일반적 함수들을 제공한다. 루아에서 문자열에 인덱스를 쓸 때는 첫 번째 글자가 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 (···)
수 코드가 반드시 플랫폼 간에 이식성이 있지는 않다.
string.dump (function [, strip])
주어진 함수의 이진 표현(바이너리 청크)을 담은
문자열을 반환한다.
이후 그 문자열에 load
하면
함수의 복사본을 (새 upvalue로) 반환한다.
strip
이 참 값이면
공간 절약을 위해 이진 표현에
함수에 대한 디버그 정보가
포함되지 않을 수도 있다.
upvalue가 있는 함수인 경우 upvalue 개수만 저장된다. (재)적재 때 그 upvalue들이 nil을 담은 새 인스턴스를 받는다. (디버그 라이브러리를 이용하면 원하는 방식으로 함수의 upvalue를 직렬화 및 재적재할 수 있다.)
string.find (s, pattern [, init [, plain]])
문자열 s
에서 pattern
의 첫 번째 일치 위치를 찾는다.
(6.4.1절 참고.)
일치하는 부분을 발견하면 시작점과 끝점의
s
내 인덱스를 반환한다.
못 찾으면 nil을 반환한다.
세 번째의 선택적 수 인자 init
은
탐색을 시작할 위치를 지정한다.
기본값은 1이며 음수일 수 있다.
네 번째의 선택적 인자 plain
에
true 값을 주면 패턴 검사 기능을 끈다.
그래서 pattern
내의 어떤 문자도 특수하게 취급하지 않고
단순한 "부분 문자열 찾기" 동작을 한다.
plain
에 값을 주려면 init
에도 주어야 한다는 점에 유의하라.
패턴에 포획이 있으면 일치 성공 시 두 인덱스 뒤에 잡힌 값들을 함께 반환한다.
string.format (formatstring, ···)
첫 번째 인자(문자열이어야 함)에 따라서
가변 개수 인자들로 만든 서식 적용 문자열을 반환한다.
서식 문자열은 ISO C 함수 sprintf
와 같은 규칙을 따른다.
다만 옵션/수식자
*
, h
, L
, l
, n
,
p
를 지원하지 않으며
추가로 q
옵션이 있다.
q
옵션은 문자열을 큰따옴표 안에 넣고
필요하면 이스케이프 열을 써서
그 결과를 루아 인터프리터가 안전하게 읽을 수 있도록 한다.
예를 들어 다음과 같이 호출하면
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 컴파일러로 루아를 컴파일하는 경우에는
옵션 A
와 a
(16진법 실수)는
어떤 수식자(플래그, 폭, 길이)도 지원하지 않는다.
옵션 s
는 문자열을 기대한다.
인자가 문자열이 아니면
tostring
과 같은 규칙에 따라 문자열로 변환한다.
옵션에 수식자(플래그, 폭, 길이)가 있는 경우에는
문자열 인자에 0이 포함돼 있지 않아야 한다.
string.gmatch (s, pattern)
s
에 대한 pattern
의 다음 포획 값들을 반환한다.
(6.4.1절 참고.)
pattern
에 포획을 지정하지 않으면
각 호출마다 일치 부분 전체를 내놓는다.
예를 들어 다음 루프는
문자열 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
이 함수면 일치가 있을 때마다
포획된 부분 문자열 모두를 순서대로 인자로 해서 그 함수를 호출한다.
어느 경우든 패턴에 포획을 지정하지 않으면 패턴 전체가 포획 안에 있는 것처럼 동작한다.
테이블 질의나 함수 호출의 반환 값이 문자열이나 수이면 치환 문자열로 쓴다. 그렇지 않고 false나 nil이면 교체하지 않는 것이다. (즉 문자열 내의 그 일치 부분을 그대로 유지한다.)
몇 가지 예를 들면 다음과 같다.
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.3"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.3.tar.gz"
string.len (s)
""
의 길이는 0이다.
문자열 내의 0도 산입된다.
따라서 "a\000bc\000"
의 길이가 5다.
string.lower (s)
string.match (s, pattern [, init])
s
에서 pattern
의 첫 번째 일치 부분을 찾는다.
(6.4.1절 참고.)
일치 부분을 발견하면
패턴의 포획 값들을 반환한다.
못 찾았으면 nil을 반환한다.
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
의 부분 문자열을 반환한다.
i
와 j
가 음수일 수 있다.
j
가 없으면 (문자열 길이와 같은) -1로 상정한다.
특히
string.sub(s,1,j)
호출은
길이 j
인 s
의 머리를 반환하고
string.sub(s, -i)
(i
는 양수) 호출은
길이 i
인 s
의 꼬리를 반환한다.
음수 인덱스 변환 후에,
i
가 1보다 작으면
1로 정정한다.
j
가 문자열 길이보다 크면
그 길이로 정정한다.
이런 정정 후에
i
가 j
보다 크면
빈 문자열을 반환한다.
string.unpack (fmt, s [, pos])
형식 문자열 fmt
에 따라 문자열 s
에 포장된
(string.pack
참고) 값들을 반환한다.
(6.4.2절 참고.)
pos
는 선택적이며 s
의 어디부터
읽기를 시작할지 표시한다. (기본값은 1이다.)
읽은 값들 뒤에
s
에서 아직 안 읽은 다음 첫 바이트의 인덱스를 함께 반환한다.
string.upper (s)
루아에서는 정규 문자열로 패턴을 기술한다.
패턴 검사 함수
string.find
,
string.gmatch
,
string.gsub
,
string.match
에서
정규 문자열을 패턴으로 해석한다.
이 절에서는 그 문자열의 문법과 의미(즉 무엇에 일치하는지)를 설명한다.
문자 클래스를 사용해 문자들의 집합을 나타낸다. 다음 요소들로 문자 클래스를 기술할 수 있다.
^$()%.[]*+-?
중 하나가 아님)
문자 x 자체를 나타낸다.
.
: (마침표) 모든 문자를 나타낸다.%a
: 모든 영문 글자를 나타낸다.%c
: 모든 제어 문자를 나타낸다.%d
: 모든 숫자를 나타낸다.%g
: 공백을 제외한 모든 출력 가능 문자를 나타낸다.%l
: 모든 소문자 글자를 나타낸다.%p
: 모든 문장 부호 문자를 나타낸다.%s
: 모든 공백 문자를 나타낸다.%u
: 모든 대문자 글자를 나타낸다.%w
: 모든 영숫자를 나타낸다.%x
: 모든 16진법 숫자를 나타낸다.%x
: (x가 영숫자 아닌 문자)
문자 x를 나타낸다.
특수 문자를 이스케이프하는 표준 방식이다.
패턴에서 영숫자 아닌 모든 문자
(특수 문자 여부 상관없이, 모든 문장 부호 포함) 앞에
'%
'를 붙여서 그 문자 자체를 나타낼 수 있다.
[set]
:
set 안의 모든 문자들의 합집합인
클래스를 나타낸다.
오름차순 범위의 끝 문자를 '-
'로 붙여 써서
문자 범위를 지정할 수 있다.
그리고 위에서 설명한 %
x 형태 클래스들을 모두
set의 요소로 쓸 수 있다.
그 외의 문자들은 set 안에서 그 자체를 나타낸다.
예를 들어 [%w_]
(또는 [_%w]
) 패턴은
모든 영숫자 문자들에 밑줄을 더한 것을 나타내고,
[0-7]
패턴은 8진법 숫자를 나타내며,
[0-7%l%-]
패턴은 8진법 숫자 더하기
소문자 글자 더하기 '-
' 문자를 나타낸다.
닫는 대괄호를 집합에 넣으려면 집합 첫 번째 문자로 두면 된다. 하이픈을 집합에 넣으려면 집합 첫 번째 문자나 마지막 문자로 두면 된다. (두 경우 모두 이스케이프를 쓸 수도 있다.)
범위와 클래스 간의 상호작용은 규정되어 있지 않다.
그러므로 [%a-z]
나 [a-%%]
같은 패턴은
의미가 없다.
[^set]
:
set의 여집합을 나타낸다.
set은 위에서처럼 해석한다.
한 글자로 나타내는 클래스 (%a
, %c
등) 모두에 대해
대응하는 대문자 글자가 그 클래스의 여집합을 나타낸다.
예를 들어 %S
는 공백이 아닌 모든 문자를 나타낸다.
글자, 공백, 기타 문자 그룹들의 정의는
현재 로캘에 따라 정해진다.
특히 클래스 [a-z]
가 %l
과 동등하지 않을 수도 있다.
다음이 패턴 항목이 될 수 있다.
*
'를 붙인 것.
클래스의 문자들이 0번 이상 반복되는 것에 일치한다.
이 반복 항목은 항상 최대한 긴 열에 일치하게 된다.
+
'를 붙인 것.
클래스의 문자들이 1번 이상 반복되는 것에 일치한다.
이 반복 항목은 항상 최대한 긴 열에 일치하게 된다.
-
'를 붙인 것.
클래스의 문자들이 0번 이상 반복되는 것에 일치한다.
'*
'와 달리
항상 최대한 짧은 열에 일치하게 된다.
?
'를 붙인 것.
클래스의 문자가 0번 또는 1번 등장하는 것에 일치한다.
가능한 경우 항상 1번 등장하는 것으로 일치한다.
%n
. n은 1에서 9까지.
이 항목은 n 번째 포획 문자열(아래 참고)과 같은 부분 문자열에 일치한다.
%bxy
. x와 y는 별개 문자.
이 항목은 x로 시작해서 y로 끝나고
x와 y가 짝이 맞는 문자열에 일치한다.
짝이 맞는다는 것은 왼쪽에서 오른쪽으로 읽어 나가면서
x에서 +1 하고 y에서 -1 한다고 할 때
0이 되는 첫 번째 y가 끝내는 y가 된다는 뜻이다.
예를 들어 %b()
항목은 짝이 맞는 괄호로 감싼 식에 일치한다.
%f[set]
. 경계(frontier) 패턴.
이 항목은 다음 문자는 set에 속하고
이전 문자는 set에 속하지 않는 위치의
빈 문자열에 일치한다.
집합 set은 앞서 설명한 대로 해석한다.
대상 문자열의 시작과 끝에
'\0
' 문자가 있는 것처럼 처리한다.
패턴은 일련의 패턴 항목들이다.
패턴 시작의 캐럿 '^
'은 일치 부분을
대상 문자열 시작점에 고정시킨다.
패턴 끝의 '$
'는 일치 부분을
대상 문자열 끝점에 고정시킨다.
다른 위치에서는 '^
'과 '$
'가
특별한 의미 없이 그 자체를 나타낸다.
패턴 안에 괄호로 둘러싸인 하위 패턴이 있을 수 있는데
그게 포획(capture)이다.
일치에 성공했을 때 포획 부분에 일치한 부분 문자열을
향후 사용을 위해 저장(포획)해 둔다.
왼쪽 괄호에 따라서 포획에 번호가 붙는다.
예를 들어 패턴 "(a*(.)%w(%s*))"
가 있을 때,
대상 문자열에서 "a*(.)%w(%s*)"
에 일치한 부분이
첫 번째 포획 값으로 저장되고 (그래서 1번이 되고),
".
"에 일치한 문자가 2번으로 포획되고,
"%s*
"에 일치한 부분이 3번이 된다.
특별히 빈 포획 ()
는
현재 문자열 위치를 (수 값으로) 포획한다.
예를 들어 문자열 "flaaap"
에 패턴 "()aa()"
를 적용하면
3과 5가 포획된다.
string.pack
,
string.packsize
,
string.unpack
의
첫 번째 인자는 만들거나 읽으려는 구조체의 레이아웃을 기술하는 형식 문자열이다.
형식 문자열은 일련의 변환 옵션들이다. 가능한 변환 옵션은 다음과 같다.
<
: 리틀 엔디안 설정>
: 빅 엔디안 설정=
: 시스템 기본 엔디안 설정![n]
: 최대 정렬 크기를 n
으로 설정
(생략 시 시스템 기본 정렬 크기)b
: 부호 있는 바이트 (char
)B
: 부호 없는 바이트 (char
)h
: 부호 있는 short
(시스템 기본 크기)H
: 부호 없는 short
(시스템 기본 크기)l
: 부호 있는 long
(시스템 기본 크기)L
: 부호 없는 long
(시스템 기본 크기)j
: lua_Integer
J
: lua_Unsigned
T
: size_t
(시스템 기본 크기)i[n]
: 부호 있는 n
바이트 int
(생략 시 시스템 기본 크기)I[n]
: 부호 없는 n
바이트 int
(생략 시 시스템 기본 크기)f
: float
(시스템 기본 크기)d
: double
(시스템 기본 크기)n
: lua_Number
cn
: n
바이트 고정 크기 문자열z
: 영 종료 문자열s[n]
: n
바이트 부호 없는 정수로
표현한 길이가 앞에 붙은 문자열
(생략 시 size_t
)x
: 패딩 1바이트Xop
: 옵션 op
의 크기에 따라
정렬을 맞춘 빈 항목
(op
는 크기만 얻고 무시)
': (공백) 무시됨
("[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
에서 무시한다.)
이 라이브러리는 기초적인 UTF-8 인코딩 지원을 제공한다.
모든 함수를 테이블 utf8
에 담아서 제공한다.
인코딩 처리 외의 유니코드 지원은 제공하지 않는다.
문자 분류처럼 문자의 의미가 필요한 동작은 지원 범위에 포함되지 않는다.
따로 명시하지 않았으면 바이트 위치를 매개변수로 받는 함수에서는 받은 위치가 바이트 열의 시작이거나 아니면 대상 문자열 길이 더하기 1이라고 상정한다. 문자열 라이브러리에서처럼 음수 인덱스는 문자열 끝부터 거꾸로 센다.
utf8.char (···)
utf8.charpattern
[\0-\x7F\xC2-\xF4][\x80-0xBF]*
"다.
(6.4.1절 참고.)
대상이 유효한 UTF-8 문자열이라고 하면
정확히 한 개의 UTF-8 바이트 열에 일치한다.
utf8.codes (s)
다음과 같이 쓰면
for p, c in utf8.codes(s) do body end
문자열 s
의 모든 문자에 대해 반복하도록 값을 반환한다.
각 문자에서 p
는 (바이트 단위) 위치이고 c
는 코드 포인트다.
유효하지 않은 바이트 열을 만나면 오류를 던진다.
utf8.codepoint (s [, i [, j]])
s
에서 바이트 위치 i
와 j
사이에서 (두 위치 포함)
시작하는 모든 문자들의 코드 포인트를 (정수로) 반환한다.
i
의 기본값은 1이고 j
의 기본값은 i
다.
유효하지 않은 바이트 열을 만나면 오류를 던진다.
utf8.len (s [, i [, j]])
s
에서 위치 i
와 j
사이에서 (두 위치 포함)
시작하는 UTF-8 문자들의 수를 반환한다.
i
의 기본값은 1이고 j
의 기본값은 -1이다.
유효하지 않은 바이트 열을 발견하면
거짓 값과 첫 번째 비유효 바이트의 위치를 반환한다.
utf8.offset (s, n [, i])
s
에서 (위치 i
부터 세어서) n
번째 문자의
인코딩이 시작되는 (바이트 단위) 위치를 반환한다.
n
이 음수면 i
번 위치 앞의 문자를 뜻한다.
i
의 기본값은 n
이 음수가 아니면 1이고,
음수면 #s + 1
이다.
그래서 utf8.offset(s, -n)
이라고 하면
문자열 끝에서 n
번째 문자의 오프셋을 얻게 된다.
지정한 문자가 대상 문자열 안이나 끝 바로 다음에 있지 않으면
nil을 반환한다.
특별히
n
이 0일 때는 s
의 i
번째 바이트를
포함하는 문자의 인코딩 시작점을 반환한다.
이 함수에서는 s
가 유효한 UTF-8 문자열이라고 가정한다.
이 라이브러리는 테이블 조작을 위한 일반적 함수들을 제공한다.
모든 함수를 테이블 table
에 담아서 제공한다.
동작에 테이블 길이가 필요한 경우마다 길이 연산자에 대한 주의 사항이 모두 적용된다. (3.4.7절 참고.) 모든 함수에서 인자로 받은 테이블의 수 아닌 키는 무시한다.
table.concat (list [, sep [, i [, j]]])
모든 항목이 문자열이나 수인 리스트를 받아서
문자열 list[i]..sep..list[i+1] ··· sep..list[j]
를 반환한다.
sep
의 기본값은 빈 문자열이고,
i
의 기본값은 1이며,
j
의 기본값은 #list
다.
i
가 j
보다 크면 빈 문자열을 반환한다.
table.insert (list, [pos,] value)
list
의 pos
위치에 항목 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
"에 인자 총개수를 넣은 새 테이블을 반환한다.
참고로 결과로 나오는 테이블이 열이 아닐 수도 있다.
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
일 수도 있다.
그 경우 항목 list[pos]
를 없앤다.
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
다.
이 라이브러리는 기초적인 수학 함수들을 제공한다.
모든 함수와 상수를 테이블 math
에 담아서 제공한다.
"정수/실수
"라고 표기한 함수는
정수 인자에 대해 정수 결과를 내놓고
실수 (또는 혼합) 인자에 대해 실수 결과를 내놓는다.
올림/내림 함수들은
(math.ceil
, math.floor
, math.modf
)
결과가 정수 범위에 들어가면 정수를 반환하고
아니면 실수를 반환한다.
math.abs (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을 향해 내림/올림하는 방식으로 x
를 y
로 나눈
나머지를 반환한다. (정수/실수)
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) 범위에 균등하게 분포하는
유사난수 실수를 반환한다.
두 정수 m
과 n
으로 호출 시
[m, n] 범위에 균등하게 분포하는
유사난수 정수를 반환한다.
(n-m 값이 음수일 수 없으며 루아 정수 범위에 들어가야 한다.)
math.random(n)
호출은 math.random(1,n)
과 동등하다.
이 함수는 C에서 제공하는 기반 유사난수 생성기의 인터페이스이다.
math.randomseed (x)
x
를 유사난수 생성기의 "시드"로 설정한다.
시드가 같으면 만들어 내는 수열이 같다.
math.sin (x)
x
의 사인을 반환한다. (라디안)
math.sqrt (x)
x
의 제곱근을 반환한다.
(식 x^0.5
로도 이 값을 계산할 수 있다.)
math.tan (x)
x
의 탄젠트를 반환한다. (라디안)
math.tointeger (x)
값 x
가 정수로 변환 가능하면 그 정수를 반환한다.
그렇지 않으면 nil을 반환한다.
math.type (x)
x
가 정수면 "integer
"를 반환하고,
실수면 "float
"을 반환하고,
x
가 수가 아니면 nil을 반환한다.
math.ult (m, n)
불리언을 반환한다.
부호 없는 정수로 비교할 때 정수 m
이 정수 n
보다 작으면,
그리고 그 경우에만 참이다.
I/O 라이브러리에서는 두 가지 파일 조작 방식을 제공한다. 첫 번째는 암묵적 파일 핸들을 사용하는 것이다. 즉, 기본 입력 파일과 기본 출력 파일을 설정하는 동작이 있고 모든 입출력 동작이 그 기본 파일에서 이뤄진다. 두 번째 방식은 명시적인 파일 핸들을 쓰는 것이다.
암묵적 파일 핸들을 쓸 때는
모든 동작이 테이블 io
에 담겨서 제공된다.
명시적 파일 핸들을 쓸 때는
io.open
동작이 파일 핸들을 반환하고
그 파일 핸들의 메소드 형태로 모든 동작이 제공된다.
테이블 io
에는 또한 미리 정의된 파일 핸들
io.stdin
,
io.stdout
,
io.stderr
가 있는데,
그 의미는 C에서와 같다.
I/O 라이브러리에서는 이 파일들을 절대 닫지 않는다.
따로 명시하지 않았으면
모든 I/O 함수는 실패 시 nil을
(그리고 두 번째 결과로 오류 메시지와
세 번째 결과로 시스템별 오류 코드를) 반환한다.
성공 시에는 nil과 다른 어떤 값을 반환한다.
오류 발생 시 오류 메시지와 오류 코드 계산에
전역 C 변수 errno
를 이용하기 때문에
POSIX를 준수하지 않는 시스템에서는
스레드에 안전하지 않을 수 있다.
io.close ([file])
file:close()
와 동등하다.
file
이 없으면 기본 출력 파일을 닫는다.
io.flush ()
io.output():flush()
와 동등하다.
io.input ([file])
파일 이름으로 호출하면 그 파일을 (텍스트 모드로) 열어서 그 핸들을 기본 입력 파일로 설정한다. 파일 핸들로 호출하면 그 파일 핸들을 기본 입력 파일로 설정하기만 한다. 인자 없이 호출하면 현재의 기본 입력 파일을 반환한다.
오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.
io.lines ([filename, ···])
지정한 파일 이름을 읽기 모드로 열어서
반복자 함수를 반환한다. 그 함수는
열린 파일의 file:lines(···)
처럼 동작한다.
반복자 함수가 파일 끝을 감지하면
(루프를 끝내기 위해) 아무 값도 반환하지 않으며 자동으로 파일을 닫는다.
(파일 이름 없는) io.lines()
호출은
io.input():lines("*l")
와 동등하다.
즉, 기본 입력 파일의 행들에 대해 반복한다.
이 경우에는 루프가 끝날 때 반복자가 파일을 닫지 않는다.
오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.
io.open (filename [, mode])
문자열 mode
에 지정한 방식으로
파일을 연다.
성공 시
새 파일 핸들을 반환한다.
mode
문자열은 다음 중 하나일 수 있다.
r
": 읽기 모드 (기본값)w
": 쓰기 모드a
": 덧붙이기 모드r+
": 수정 모드, 이전 데이터 모두 유지w+
": 수정 모드, 이전 데이터 모두 삭제a+
": 덧붙이기 수정 모드, 이전 데이터 유지하고
파일 끝에서만 쓰기 가능
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
가 파일 핸들이 아니면 nil을 반환한다.
io.write (···)
io.output():write(···)
와 동등하다.
file:close ()
file
을 닫는다.
참고로 파일 핸들이 쓰레기로 수집될 때
파일이 자동으로 닫힌다.
하지만 얼마나 지나서 그렇게 될지 예측할 수 없다.
io.popen
으로 만든 파일 핸들을 닫을 때
file:close
는
os.execute
와 같은 값들을 반환한다.
file:flush ()
file
에 쓴 데이터를 저장한다.
file:lines (···)
반복자 함수를 반환한다.
호출할 때마다 그 함수는
지정한 형식에 따라 파일을 읽어 들인다.
형식을 주지 않으면
기본으로 "l
"을 쓴다.
예를 들어 다음처럼 쓰면
for c in file:lines(1) do body end
현재 위치부터
파일의 모든 문자들에 대해 반복하게 된다.
io.lines
와 달리
이 함수는 루프가 끝날 때 파일을 닫지 않는다.
오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.
file:read (···)
지정한 형식들에 따라 파일 file
을 읽는다.
각 형식에 대해 읽어 들인 문자들을 가지고 문자열이나 수를 반환하며,
지정한 형식으로 데이터를 읽을 수 없으면 nil을 반환한다.
(그 경우 이어지는 형식들은 읽지 않는다.)
형식 없이 호출할 때의
기본 형식은 다음 행 읽기다.
(아래 참고.)
사용 가능한 형식은 다음과 같다.
n
":
루아 어휘 규정에 따라
수를 읽어서 실수나 정수로 반환한다.
(숫자 앞에 공백과 부호가 올 수 있다.)
이 형식에서는 입력 열이 유효한 수 시작부면
항상 최대한 읽어 들인다.
그 시작부가 유효한 수로 이어지지 않으면
(예: 빈 문자열, "0x
", "3.4e-
")
버리고서 nil을 반환한다.
a
":
현재 위치부터 파일을 통째로 읽어 들인다.
파일 끝에서는 빈 문자열을 반환한다.
l
":
다음 행을 읽어 들이며 개행을 생략한다.
파일 끝에서는 nil을 반환한다.
기본 형식이다.
L
":
다음 행을 읽어 들이며 개행 문자가 있으면 유지한다.
파일 끝에서는 nil을 반환한다.
수
가 0이면
아무것도 읽지 않고 빈 문자열을 반환하되,
파일 끝이면 nil을 반환한다.
형식 "l
"과 "L
"은 텍스트 파일에만 써야 할 것이다.
file:seek ([whence [, offset]])
파일 위치를
다음과 같이 문자열 whence
로 나타낸 기준점에
offset
을 더한 위치로 설정하고,
파일 시작점을 기준으로 한 파일 위치를 얻는다.
set
": 위치 0(파일 시작점) 기준cur
": 현재 위치 기준end
": 파일 끝 기준
성공 시 seek
은 파일 시작점부터 바이트 단위로 잰
최종 파일 위치를 반환한다.
실패하면 nil과
오류 설명 문자열을 반환한다.
whence
의 기본값은 "cur"
이고
offset
은 0이다.
그래서 file:seek()
호출은 현재 파일 위치를
변경 없이 반환한다.
file:seek("set")
호출은 위치를 파일 시작으로
설정한다. (그리고 0을 반환한다.)
file:seek("end")
호출은 위치를 파일 끝으로
설정하고 파일 크기를 반환한다.
file:setvbuf (mode [, size])
출력 파일의 버퍼링 방식을 설정한다. 세 가지 방식이 있다.
no
":
버퍼링 없음. 출력 동작의 결과가 즉시 나타난다.
full
":
최대 버퍼링. 버퍼가 가득 차거나
명시적으로 파일에 flush
할 때만 (io.flush
참고)
출력 동작을 수행한다.
line
":
행 버퍼링. 개행을 출력하거나
어떤 (터미널 장치 같은) 특수 파일에서 입력을 읽을 때까지
출력을 버퍼에 저장한다.
뒤의 두 경우에서 size
가
바이트 단위 버퍼 크기를 지정한다.
기본값은 적절한 크기다.
file:write (···)
인자 각각의 값을 file
에 쓴다.
인자는 문자열이나 수여야 한다.
성공 시 이 함수는 file
을 반환한다.
아니면 nil과 오류 설명 문자열을 반환한다.
이 라이브러리는 테이블 os
를 통해 구현되어 있다.
os.clock ()
프로그램이 사용한 CPU 시간의 초 단위 근삿값을 반환한다.
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
과 같은 규칙에 따라 서식을 준
문자열로 일시를 반환한다.
인자 없이 호출 시에는
호스트 시스템과 현재 로캘에 따라
적당하게 표현한 날짜와 시간을 반환한다.
(구체적으로 말해 os.date()
는 os.date("%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고,
아니면 nil이다.
그 첫 번째 결과에 더해서
다음과 같이 문자열과 수를 반환한다.
exit
":
명령이 정상적으로 종료되었다.
이어지는 수는 명령의 종료 상태 값이다.
signal
":
명령이 시그널에 의해 종료되었다.
이어지는 수는 명령을 끝낸 시그널 번호다.
command
없이 호출 시
os.execute
는 불리언을 반환하는데, 셸이 사용 가능한 경우 참이다.
os.exit ([code [, close]])
ISO C 함수 exit
을 호출해서 호스트 프로그램을 종료한다.
code
가 true면
상태로 EXIT_SUCCESS
를 반환한다.
code
가 false면
상태로 EXIT_FAILURE
를 반환한다.
code
가 수이면
상태가 그 수를 반환한다.
code
의 기본값은 true다.
선택적인 두 번째 인자 close
가 참이면
끝내기 전에 루아 상태를 닫는다.
os.getenv (varname)
프로세스 환경 변수 varname
의 값을 반환한다.
그 변수가 정의되어 있지 않으면 nil을 반환한다.
os.remove (filename)
지정한 이름의 파일을 (POSIX 시스템에서는 빈 디렉터리도 가능) 삭제한다. 실패하면 nil에 더해서 오류 설명 문자열과 오류 코드를 반환한다. 아니면 참을 반환한다.
os.rename (oldname, newname)
이름이 oldname
인 파일이나 디렉터리의
이름을 newname
으로 바꾼다.
실패하면 nil에 더해서
오류 설명 문자열과 오류 코드를 반환한다.
아니면 참을 반환한다.
os.setlocale (locale [, category])
프로그램의 현재 로캘을 설정한다.
locale
은 로캘을 지정하는 시스템별 문자열이다.
category
는 바꿀 범주를 나타내는 선택적 문자열이다.
"all"
, "collate"
, "ctype"
,
"monetary"
, "numeric"
, "time"
중 하나이며,
기본 범주는 "all"
이다.
새 로캘의 이름을 반환하며,
요청에 응할 수 없으면 nil을 반환한다.
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.date
와 os.difftime
의 인자로만 쓸 수 있다.
os.tmpname ()
임시 파일에 쓸 수 있는 파일 이름을 문자열로 반환한다. 사용 전에 파일을 명시적으로 열어야 하며 더는 필요 없을 때 명시적으로 삭제해야 한다.
POSIX 시스템에서 이 함수는 보안상 위험을 피하기 위해 (이름을 얻는 시점과 파일을 생성하는 시점 사이에 다른 누군가가 잘못된 권한으로 그 파일을 생성할 수도 있다.) 그 이름으로 파일을 만들기까지 한다. 사용하려면 마찬가지로 파일을 열어야 하며 (사용하지 않은 경우에도) 파일을 삭제해야 한다.
가능하다면
프로그램이 끝날 때 파일을 자동으로 삭제해 주는
io.tmpfile
을 쓰는 게 바람직할 수 있다.
이 라이브러리는 디버그 인터페이스(4.9절)의 기능들을 루아 프로그램에 제공한다. 이 라이브러리를 사용할 때는 주의를 기울여야 한다. 여러 함수가 루아 코드에 대한 기본적인 가정(예를 들면 외부에서 함수의 지역 변수에 접근할 수 없고, 루아 코드에서 userdata 메타데이터를 바꿀 수 없고, 루아 프로그램이 죽지 않음)을 깨며, 그래서 안전했을 코드를 위험한 상태로 만들 수 있다. 또한 이 라이브러리의 일부 함수들은 느릴 수 있다.
이 라이브러리의 모든 함수들을
debug
테이블에 담아서 제공한다.
스레드를 대상으로 동작하는 함수들에는
대상 스레드를 나타내는
선택적인 첫 번째 인자가 있다.
기본값은 항상 현재 스레드다.
debug.debug ()
대화형 모드로 들어가서
사용자가 입력하는 각 문자열을 실행한다.
간단한 명령들과 다른 디버그 기능들을 이용해
전역 및 지역 변수를 조사하고,
그 값을 바꾸고, 식을 평가하는 등의 일을 할 수 있다.
단어 cont
만 있는 행을 입력하면 이 함수가 끝나고
호출자가 실행을 이어 나간다.
참고로 debug.debug
에서의 명령은 문법적으로 어떤 함수에도
포함되지 않으며, 따라서 지역 변수에 직접 접근하지 못한다.
debug.gethook ([thread])
스레드의 현재 훅 설정을
(debug.sethook
함수로 설정한 대로)
세 값(현재 훅 함수, 현재 훅 마스크, 현재 훅 카운트)으로 반환한다.
debug.getinfo ([thread,] f [, what])
함수에 대한 정보를 담은 테이블을 반환한다.
f
의 값으로 직접 함수를 줄 수도 있고 수를 줄 수도 있다.
수는 지정한 스레드의 호출 스택 f
번 단계에서
실행 중인 함수를 뜻한다.
0번 단계는 현재 함수(getinfo
자체)이고
1번 단계는 getinfo
를 호출한 함수인 식이다.
(꼬리 호출은 스택에서 자리를 차지하지 않으므로 제외된다.)
f
가 활성 함수 개수보다 큰 수이면
getinfo
가 nil을 반환한다.
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이 첫 번째 가변 인자다.
지정한 인덱스의 변수가 없으면 nil을 반환하며,
범위 밖의 단계로 호출하면 오류를 던진다.
(debug.getinfo
를 호출해서 단계가 유효한지 확인할 수 있다.)
'(
' (여는 괄호)로 시작하는 변수 이름은
이름을 모르는 변수(루프 제어 변수 같은 내부 변수나
디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.
매개변수 f
가 함수일 수도 있다.
그 경우 getlocal
은 그 함수 매개변수들의 이름만 반환한다.
debug.getmetatable (value)
지정한 value
의 메타테이블을 반환한다.
메타테이블을 가지고 있지 않으면 nil을 반환한다.
debug.getregistry ()
레지스트리 테이블을 반환한다. (4.5절 참고.)
debug.getupvalue (f, up)
함수 f
에서 인덱스가 up
인 upvalue의
이름과 값을 반환한다.
지정한 인덱스의 upvalue가 없으면 nil을 반환한다.
'(
' (여는 괄호)로 시작하는 변수 이름은
이름을 모르는 변수(디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.
debug.getuservalue (u)
u
에 연계된 루아 값을 반환한다.
u
가 full userdata가 아니면 nil을 반환한다.
debug.sethook ([thread,] hook, mask [, count])
지정한 함수를 훅으로 설정한다.
문자열 mask
와 수 count
로
언제 훅이 호출되어야 하는지 지정한다.
문자열 mask
에서 다음 문자들을 조합할 수 있다.
c
': 루아가 함수를 호출할 때마다 훅이 호출된다.r
': 루아가 함수에서 반환할 때마다 훅이 호출된다.l
': 루아가 새 코드 행에 들어갈 때마다 훅이 호출된다.
그리고
count
가 0이 아니면
count
개 인스트럭션마다 훅이 호출된다.
인자 없이 호출하면 훅을 끈다.
훅이 호출될 때 받는 첫 번째 인자는
그 호출을 유발한 이벤트를 기술하는 문자열이다.
"call"
(또는 "tail call"
),
"return"
,
"line"
, "count"
중 하나다.
행 이벤트에서는
훅의 두 번째 매개변수로 새 행 번호를 받는다.
훅 안에서 단계를 2로 해서 getinfo
를 호출하면
실행 중인 함수에 대한 추가 정보를 얻을 수 있다.
(0번 단계는 getinfo
함수고
1번 단계는 훅 함수다.)
debug.setlocal ([thread,] level, local, value)
스택의 level
단계에 있는 함수에서
인덱스가 local
인 지역 변수에 값 value
를 할당한다.
지정한 인덱스의 지역 변수가 없으면 nil을 반환하며,
범위 밖의 level
로 호출하면 오류를 던진다.
(getinfo
를 호출해서 단계가 유효한지 확인할 수 있다.)
그 외 경우에는 그 지역 변수의 이름을 반환한다.
변수 인덱스와 이름에 대한 자세한 내용은
debug.getlocal
을 보라.
debug.setmetatable (value, table)
(nil일 수 있는) 지정한 table
을
지정한 value
의 메타테이블로 설정한다.
value
를 반환한다.
debug.setupvalue (f, up, value)
함수 f
에서 인덱스가 up
인 upvalue에
값 value
를 할당한다.
지정한 인덱스의 upvalue가 없으면 nil을 반환한다.
그 외 경우에는 그 upvalue의 이름을 반환한다.
debug.setuservalue (udata, value)
지정한 value
를
지정한 udata
에 연계된 루아 값으로 설정한다.
udata
가 full userdata여야 한다.
udata
를 반환한다.
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)
루아 클로저 f1
의 n1
번째 upvalue가
루아 클로저 f2
의 n2
번째 upvalue를 가리키게 만든다.
루아는 호스트 C 프로그램에 내장되는 확장 언어로 설계되었지만
단독 언어로도 자주 쓰인다.
단독 언어 루아를 위한
lua
라는 인터프리터가
표준 배포 파일에 딸려 있다.
단독 인터프리터에는
디버그 라이브러리를 포함한
모든 표준 라이브러리가 포함되어 있다.
사용법은 이렇다.
lua [options] [script [args]]
옵션은 이렇다.
-e stat
: 문자열 stat 실행-l mod
: mod를 "require" 하고
결과를 전역 @mod에 할당-i
: script 실행 후 대화형 모드 진입-v
: 버전 정보 출력-E
: 환경 변수 무시--
: 옵션 처리 중단-
: stdin
을 파일처럼 실행하고 옵션 처리 중단
lua
는 옵션들을 처리한 후 주어진 script를 실행한다.
lua
를 인자 없이 호출하면
표준 입력(stdin
)이 터미널일 때는 lua -v -i
처럼 동작하고
아닐 때는 lua -
처럼 동작한다.
-E
옵션 없이 호출 시
인터프리터는 인자 실행에 앞서
환경 변수 LUA_INIT_5_3
을
(버전 붙은 이름이 정의되어 있지 않으면 LUA_INIT
을) 확인한다.
변수 내용이 @파일명
형식이면
lua
가 그 파일을 실행한다.
그렇지 않으면 lua
가 그 문자열 자체를 실행한다.
-E
옵션을 줘서 호출 시
루아는 LUA_INIT
과 더불어
LUA_PATH
와 LUA_CPATH
의 값도 무시하며,
package.path
와 package.cpath
의 값을
luaconf.h
에 정의된 기본 경로로 설정한다.
-i
와 -E
를 제외한 모든 옵션들을 순서대로 처리한다.
예를 들어 다음과 같이 호출 시,
$ lua -e'a=1' -e 'print(a)' script.lua
먼저 a
를 1로 설정하고, 다음으로 a
의 값을 찍고,
마지막으로 인자 없이 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
프로그램을 루아 5.2에서 루아 5.3으로 옮기면서
발견할 수 있는 비호환 사항들을 나열한다.
어떤 사항들은 적절한 옵션을 써서 루아를 컴파일하는 것으로
(파일 luaconf.h
참고) 피할 수 있다.
하지만 그 호환성 옵션들은 향후에 모두 없어질 것이다.
루아 버전이 바뀔 때 상수의 숫자 값이나 매크로 함수의 구현처럼 프로그램 소스 코드 변경이 필요치 않은 방식으로는 언제든 C API가 바뀔 수 있다. 따라서 루아 버전들 간에 바이너리가 호환된다고 가정해선 안 된다. 항상 루아 API 사용 프로그램을 새 버전으로 다시 컴파일해야 한다.
또한 루아 버전이 바뀌면서 언제든 사전 컴파일 청크의 내부 표현 방식이 바뀔 수 있다. 즉, 루아 버전들 간에 사전 컴파일 청크가 호환되지 않는다.
공식 배포본 내의 표준 경로가 버전들 간에 바뀔 수 있다.
그 차이를 고치려면 모든 수를 실수로 만들면 된다.
(루아 5.2에서는 모든 수가 실수였다.)
말하자면 상수 끝에 .0
을 써 주고
x = x + 0.0
으로 변수를 변환하는 것이다.
(이 방법은 드물게 있는 비호환 코드를
얼른 고치기 위한 것이지
좋은 프로그램을 위한 일반적 지침은 아니다.
좋은 프로그램을 위해선
실수가 필요한 곳에 실수를 쓰고
정수가 필요한 곳에 정수를 쓰면 된다.)
.0
을 붙인다.
(예를 들어 실수 2.0이 2
가 아니라
2.0
으로 찍히게 된다.)
수에 특정 형식이 필요할 때는 항상
명시적으로 서식을 사용해야 한다.
(이는 공식적으로는 비호환 사항이 아니다. 수를 문자열로 바꿀 때의 형식을 루아에서 명세하지 않기 때문이다. 하지만 일부 프로그램들에선 특정 형식을 가정했다.)
bit32
라이브러리가 폐기 예정이 되었다.
호환되는 외부 라이브러리를 요청하거나,
더 바람직하게는 그 함수들을 적절한 비트 연산으로 바꿀 수 있다.
(bit32
는 32비트 정수에 대해 동작하는 반면
루아 5.3의 비트 연산자는 기본적으로 64비트인
루아 정수에 대해 동작한다는 점에 유의해야 한다.)
ipairs
반복자에서 이제 메타메소드를 존중하며
__ipairs
메타메소드가 폐기 예정이 되었다.
io.read
의 옵션 이름이 더는 '*
'로 시작하지 않는다.
호환성을 위해 루아에서 그 문자를 계속 받아들일 (그리고 무시할) 것이다.
atan2
, cosh
, sinh
, tanh
, pow
,
frexp
, ldexp
가 폐기 예정이 되었다.
math.pow(x,y)
는 x^y
로 대체할 수 있다.
math.atan2
는 인자를 한 개 또는 두 개 받는 math.atan
로
대체할 수 있다.
math.ldexp(x,exp)
는 x * 2.0^exp
로 대체할 수 있다.
다른 연산들은
외부 라이브러리를 사용하거나 루아로 구현할 수 있다.
require
에서 C 적재 함수를
탐색할 때 버전 붙은 이름을 다루는 방식이 바뀌었다.
이제 버전이 (다른 대다수 도구들에서처럼)
모듈 이름 뒤에 와야 한다.
호환성을 위해 탐색 함수에서 새 형식으로 열기 함수를 찾을 수 없으면
여전히 이전 형식을 시도한다.
(루아 5.2에서 이미 이렇게 동작했지만
그 내용을 기록하지 않았다.)
collectgarbage("count")
호출이 이제 결과를 한 개만 반환한다.
(첫 번째 결과의 소수 부분을 가지고
그 두 번째 결과를 계산할 수 있다.)
lua_getctx
를 통해 얻어야 했던 것들을
이제는 인자로 받으며,
그래서 lua_getctx
가 제거되었다.
그에 맞게 코드를 고쳐야 한다.
lua_dump
에 매개변수 strip
이 추가되었다.
이 매개변수 값으로 0을 쓰면 이전 동작 방식이다.
lua_pushunsigned
, lua_tounsigned
, lua_tounsignedx
,
luaL_checkunsigned
, luaL_optunsigned
)
폐기 예정이 되었다.
타입을 변환해서 부호 있는 정수용 버전을 쓰면 된다.
luaL_checkint
, luaL_optint
, luaL_checklong
, luaL_optlong
)
폐기 예정이 되었다.
타입을 변환해서 lua_Integer
용 버전을 쓰면 된다.
(또는 가능하다면 코드에서 lua_Integer
를 쓰면 된다.)
다음은 확장 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 namelist [‘=’ explist] 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 | ‘#’ | ‘~’