이매지네이션 라이브러리

KOR ENG

루아 5.4 참조 매뉴얼(Lua 5.4 Reference Manual)

2021. 1. 12. 23:17

루아 5.4 참조 매뉴얼(Lua 5.4 Reference Manual)

공유하기

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

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

 

 

1 –소개

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

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

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

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

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

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

2 –기본 개념

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

2.1 –값과 타입

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2.2 –환경과 전역 환경

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

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

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

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

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

2.3 –오류 처리

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • __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:작거나 같음 (<=) 연산. 작음 연산과 비슷하게 동작.

  • __index:인덱스 이용 접근 연산table[key].table이 테이블이 아니거나table내에key가 없을 때 이 이벤트가 일어난다.table의 메타테이블에서 메타값을 찾는다.

    이 이벤트에 대한 메타값은 함수일 수도 있고, 테이블일 수도 있고, 메타값__index가 있는 임의 값일 수도 있다. 함수인 경우table과key를 인자로 해서 호출하며 호출 결과가 (한 개 값으로 조정돼서) 연산 결과가 된다. 그 외 경우에는 그 메타값에key를 인덱스로 쓴 결과가 최종 결과이다. 이 인덱스 사용은 raw가 아니라 정규 방식이며, 따라서 또 다른__index메타값을 동작시킬 수 있다.

  • __newindex:인덱스 할당table[key] = value. index 이벤트에서처럼table이 테이블이 아니거나table내에key가 없을 때 이 이벤트가 일어난다.table의 메타테이블에서 메타값을 찾는다.

    index에서처럼 이 이벤트에 대한 메타메소드는 함수일 수도 있고, 테이블일 수도 있고, 메타값__newindex가 있는 임의 값일 수도 있다. 함수인 경우table,key,value를 인자로 해서 호출한다. 그 외 경우에는 같은 키와 값으로 그 메타값에 인덱스 할당을 반복한다. 그 할당은 raw가 아니라 정규 방식이며, 따라서 또 다른__newindex메타값을 동작시킬 수 있다.

    __newindex메타값이 호출될 때는 루아가 절대 단순 할당을 수행하지 않는다. 필요하면 메타메소드 자체에서rawset을 호출해서 직접 할당을 할 수 있다.

  • __call:호출 연산func(args). 루아에서 함수 아닌 값을 호출하려 할 때 (즉func가 함수가 아닐 때) 이 이벤트가 일어난다.func에서 메타메소드를 찾는다. 존재하는 경우func를 첫 번째 인자로 하고 이어서 원래 호출의 인자들(args)이 오게 해서 메타메소드를 호출한다. 호출 결과 모두가 연산 결과가 된다. 복수 개 결과를 허용하는 유일한 메타메소드이다.

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

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

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

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

2.5 –쓰레기 수집

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

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

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

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

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

2.5.1 –점진식 쓰레기 수집

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

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

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

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

2.5.2 –세대식 쓰레기 수집

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

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

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

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

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

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

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

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

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

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

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

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

2.5.4 –약한 테이블

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

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

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

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

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

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

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

2.6 –코루틴

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

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

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

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

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

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

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

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

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

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

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

3 –언어

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

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

3.1 –어휘 규정

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

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

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

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

루아는 대소문자를 구별하는 언어다. 그래서and는 예약 단어지만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진수 열이다. 이 코드 포인트는231보다 작은 어떤 값이든 가능하다. (루아에서는 자체적인 UTF-8 명세를 사용하며, 그래서 유효한 유니코드 코드 포인트들로 한정하지 않는다.)

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

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

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

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

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

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

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

3 345 0xff 0xBEBADA

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

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

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

3.2 –변수

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

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

var ::= Name

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

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

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

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

var ::= prefixexp ‘[’ exp ‘]

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

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

var ::= prefixexp ‘.’ Name

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

3.3 –문

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

3.3.1 –블록

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

block ::= {stat}

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

stat ::= ‘;

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

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

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

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

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

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

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

stat ::= do block end

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

3.3.2 –청크

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

chunk ::= block

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

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

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

3.3.3 –할당

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

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

식은3.4절에서 논의한다.

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

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

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

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

x, y = y, x

x와y의 값을 교환한다. 그리고 다음은

x, y, z = y, z, x

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

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

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

3.3.4 –제어 구조

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

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

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

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

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

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

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

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

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

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

stat ::= break

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

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

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

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

3.3.5 –for 문

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

수열형for루프

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

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

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

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

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

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

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

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

일반형for루프

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

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

다음for문이

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

다음처럼 동작한다.

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

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

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

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

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

3.3.6 –함수 호출 문

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

stat ::= functioncall

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

3.3.7 –지역 선언

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

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

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

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

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

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

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

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

3.3.8 –자동 닫힘 변수

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

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

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

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

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

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

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

3.4 –식

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

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

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

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

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

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

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

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

3.4.1 –산술 연산자

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

  • +:덧셈
  • -:뺄셈
  • *:곱셈
  • /:실수 나눗셈
  • //:내림 나눗셈
  • %:모듈로
  • ^:누승
  • -:단항 마이너스

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

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

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

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

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

3.4.2 –비트 연산자

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

  • &:비트 AND
  • |:비트 OR
  • ~:비트 배타적 OR
  • >>:오른쪽 시프트
  • <<:왼쪽 시프트
  • ~:단항 비트 NOT

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

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

3.4.3 –타입 강제와 변환

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

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

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

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

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

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

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

3.4.4 –관계 연산자

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

  • ==:같음
  • ~=:같지 않음
  • <:작음
  • >:
  • <=:작거나 같음
  • >=:크거나 같음

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

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

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

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

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

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

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

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

3.4.5 –논리 연산자

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

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

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

3.4.6 –접합

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

3.4.7 –길이 연산자

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

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

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

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

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

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

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

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

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

3.4.8 –우선순위

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

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

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

3.4.9 –테이블 생성자

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

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

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

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

다음과 동등하다.

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

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

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

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

3.4.10 –함수 호출

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

functioncall ::= prefixexp args

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

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

functioncall ::= prefixexp ‘:’ Name args

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

인자 문법은 다음과 같다.

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

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

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

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

3.4.11 –함수 정의

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

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

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

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

다음 문은

function f () body end

다음으로 바뀐다.

f = function () body end

다음 문은

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

다음으로 바뀐다.

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

다음 문은

local function f () body end

다음으로 바뀐다.

local f; f = function () body end

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

local f = function () body end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3.5 –가시성 규칙

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4.1 –스택

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

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

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

4.1.1 –스택 크기

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

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

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

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

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

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

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

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

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

4.2 –C 클로저

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

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

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

4.5 –레지스트리

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

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

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

  • LUA_RIDX_MAINTHREAD:레지스트리의 이 인덱스에는 상태의 주 스레드가 있다. (주 스레드는 상태와 함께 생성된 스레드다.)
  • LUA_RIDX_GLOBALS:레지스트리의 이 인덱스에는 전역 환경이 있다.

4.4 –C에서의 오류 처리

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

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

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

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

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

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

4.4.1 –상태 코드

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

  • LUA_OK(0):오류 없음.
  • LUA_ERRRUN:런타임 오류.
  • LUA_ERRMEM:메모리 할당 오류. 이 오류에 대해선 루아가 메시지 핸들러를 호출하지 않는다.
  • LUA_ERRERR:메시지 핸들러 실행 중 오류.
  • LUA_ERRSYNTAX:사전 컴파일 중 구문 오류.
  • LUA_YIELD:스레드(코루틴)가 양보함.
  • LUA_ERRFILE:파일 관련 오류. 예를 들면 파일을 열거나 읽을 수 없음.

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

4.5 –C에서의 양보 처리

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

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

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

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

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

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

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

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

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

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

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

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

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

4.6 –함수와 타입

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

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

lua_absindex

[-0, +0, –]

int lua_absindex (lua_State *L, int idx);

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

lua_Alloc

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

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

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

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

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

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

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

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

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

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

lua_arith

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

void lua_arith (lua_State *L, int op);

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

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

  • LUA_OPADD:덧셈 수행 (+)
  • LUA_OPSUB:뺄셈 수행 (-)
  • LUA_OPMUL:곱셈 수행 (*)
  • LUA_OPDIV:실수 나눗셈 수행 (/)
  • LUA_OPIDIV:내림 나눗셈 수행 (//)
  • LUA_OPMOD:모듈로 수행 (%)
  • LUA_OPPOW:누승 수행 (^)
  • LUA_OPUNM:반수 만들기 수행 (단항-)
  • LUA_OPBNOT:비트 NOT 수행 (~)
  • LUA_OPBAND:비트 AND 수행 (&)
  • LUA_OPBOR:비트 OR 수행 (|)
  • LUA_OPBXOR:비트 배타적 OR 수행 (~)
  • LUA_OPSHL:왼쪽 시프트 수행 (<<)
  • LUA_OPSHR:오른쪽 시프트 수행 (>>)

lua_atpanic

[-0, +0, –]

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

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

lua_call

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

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

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

호출을 하려면 규약을 따라야 한다. 먼저 호출할 함수를 스택에 집어넣는다. 다음으로 호출 인자들을 정순서로 집어넣는다. 즉, 첫 번째 인자를 첫 번째로 집어넣는다. 마지막으로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.5절참고.)

lua_CFunction

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

C 함수 타입.

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

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

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

lua_checkstack

[-0, +0, –]

int lua_checkstack (lua_State *L, int n);

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

lua_close

[-0, +0, –]

void lua_close (lua_State *L);

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

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

lua_compare

[-0, +0,e]

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

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

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

  • LUA_OPEQ:같은지 비교 (==)
  • LUA_OPLT:작은지 비교 (<)
  • LUA_OPLE:작거나 같은지 비교 (<=)

lua_concat

[-n, +1,e]

void lua_concat (lua_State *L, int n);

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

lua_copy

[-0, +0, –]

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

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

lua_createtable

[-0, +1,m]

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

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

lua_dump

[-0, +0, –]

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

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

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

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

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

lua_error

[-1, +0,v]

int lua_error (lua_State *L);

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

lua_gc

[-0, +0, –]

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

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

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

  • LUA_GCCOLLECT:쓰레기 수집 주기 한 번을 수행한다.
  • LUA_GCSTOP:쓰레기 수집기를 멈춘다.
  • LUA_GCRESTART:쓰레기 수집기를 다시 시작한다.
  • LUA_GCCOUNT:루아에서 현재 사용 중인 메모리의 (kB 단위) 양을 반환한다.
  • LUA_GCCOUNTB:루아에서 현재 사용 중인 메모리의 바이트 양을 1024로 나눈 나머지를 반환한다.
  • LUA_GCSTEP(int stepsize):stepsizekB 할당에 해당하는 쓰레기 수집의 점진 단계 한 번을 수행한다.
  • LUA_GCISRUNNING:수집기가 동작 중인지 (즉 중단되지 않았는지를) 알려 주는 불리언을 반환한다.
  • LUA_GCINC(int pause, int stepmul, stepsize):수집기를 지정한 매개변수들을 쓰는 점진 방식으로 바꾼다. (2.5.1절참고.) 이전 모드(LUA_GCGEN또는LUA_GCINC)를 반환한다.
  • LUA_GCGEN(int minormul, int majormul):수집기를 지정한 매개변수들을 쓰는 세대 방식으로 바꾼다. (2.5.2절참고.) 이전 모드(LUA_GCGEN또는LUA_GCINC)를 반환한다.

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

lua_getallocf

[-0, +0, –]

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

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

lua_getfield

[-0, +1,e]

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

값t[k]를 스택에 집어넣는다. 여기서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_getiuservalue

[-0, +1, –]

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

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

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

lua_insert

[-1, +1, –]

void lua_insert (lua_State *L, int index);

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

lua_Integer

typedef ... lua_Integer;

루아 정수 타입.

기본적으로 이 타입은long long(보통 64비트 2의 보수 정수)이다. 하지만long이나int(보통 32비트 2의 보수 정수)로 바꿀 수 있다. (luaconf.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.5절참고.)

lua_len

[-0, +1,e]

void lua_len (lua_State *L, int index);

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

lua_load

[-0, +1, –]

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

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

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

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

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

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

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

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

lua_newstate

[-0, +0, –]

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

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

lua_newtable

[-0, +1,m]

void lua_newtable (lua_State *L);

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

lua_newthread

[-0, +1,m]

lua_State *lua_newthread (lua_State *L);

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

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

lua_newuserdatauv

[-0, +1,m]

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

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

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

lua_next

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

int lua_next (lua_State *L, int index);

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

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

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

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

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

lua_Number

typedef ... lua_Number;

루아 실수 타입.

기본적으로 이 타입은 double이다. 하지만 단정밀도 float이나 long double로 바꿀 수 있다. (luaconf.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_OK,LUA_ERRRUN,LUA_ERRMEM,LUA_ERRERR중 하나를 반환한다.

lua_pcallk

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

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

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

lua_pop

[-n, +0, –]

void lua_pop (lua_State *L, int n);

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

lua_pushboolean

[-0, +1, –]

void lua_pushboolean (lua_State *L, int b);

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

lua_pushcclosure

[-n, +1,m]

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

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

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

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

n의 최댓값은 255다.

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

lua_pushcfunction

[-0, +1, –]

void lua_pushcfunction (lua_State *L, lua_CFunction f);

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

lua_pushfstring

[-0, +1,v]

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

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

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

lua_pushglobaltable

[-0, +1, –]

void lua_pushglobaltable (lua_State *L);

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

lua_pushinteger

[-0, +1, –]

void lua_pushinteger (lua_State *L, lua_Integer n);

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

lua_pushlightuserdata

[-0, +1, –]

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

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

루아에서 userdata는 C의 값을 나타낸다.light 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,v]

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

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

lua_rawequal

[-0, +0, –]

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

인덱스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, –]

lua_Unsigned lua_rawlen (lua_State *L, int index);

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

lua_rawset

[-2, +0,m]

void lua_rawset (lua_State *L, int index);

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

lua_rawseti

[-1, +0,m]

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

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

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

lua_rawsetp

[-1, +0,m]

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

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

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

lua_Reader

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

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

lua_register

[-0, +0,e]

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

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

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

lua_remove

[-1, +0, –]

void lua_remove (lua_State *L, int index);

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

lua_replace

[-1, +0, –]

void lua_replace (lua_State *L, int index);

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

lua_resetthread

[-0, +?, –]

int lua_resetthread (lua_State *L);

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

lua_resume

[-?, +?, –]

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

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

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

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

매개변수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_setiuservalue

[-1, +0, –]

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

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

lua_setmetatable

[-1, +0, –]

int lua_setmetatable (lua_State *L, int index);

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

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

lua_settable

[-2, +0,e]

void lua_settable (lua_State *L, int index);

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

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

lua_settop

[-?, +?, –]

void lua_settop (lua_State *L, int index);

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

lua_setwarnf

[-0, +0, –]

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

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

lua_State

typedef struct lua_State lua_State;

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

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

lua_status

[-0, +0, –]

int lua_status (lua_State *L);

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

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

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

lua_stringtonumber

[-0, +1, –]

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

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

lua_toboolean

[-0, +0, –]

int lua_toboolean (lua_State *L, int index);

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

lua_tocfunction

[-0, +0, –]

lua_CFunction lua_tocfunction (lua_State *L, int index);

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

lua_toclose

[-0, +0,v]

void lua_toclose (lua_State *L, int index);

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

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

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

lua_tointeger

[-0, +0, –]

lua_Integer lua_tointeger (lua_State *L, int index);

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,LUA_TNUMBER,LUA_TBOOLEAN,LUA_TSTRING,LUA_TTABLE,LUA_TFUNCTION,LUA_TUSERDATA,LUA_TTHREAD,LUA_TLIGHTUSERDATA중 하나다.

lua_typename

[-0, +0, –]

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

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

lua_Unsigned

typedef ... lua_Unsigned;

lua_Integer의 부호 없는 버전.

lua_upvalueindex

[-0, +0, –]

int lua_upvalueindex (int i);

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

lua_version

[-0, +0, –]

lua_Number lua_version (lua_State *L);

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

lua_WarnFunction

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

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

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

lua_warning

[-0, +0, –]

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

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

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

lua_Writer

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

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

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

lua_xmove

[-?, +?, –]

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

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

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

lua_yield

[-?, +?,v]

int lua_yield (lua_State *L, int nresults);

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

lua_yieldk

[-?, +?,v]

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

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

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

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

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

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

4.7 –디버그 인터페이스

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

lua_Debug

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

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

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

  • source:함수를 만든 청크의 출처.source가 '@'로 시작하면 함수가 파일에 정의되어 있었다는 뜻이고 '@' 다음이 그 파일의 이름이다.source가 '='로 시작하면 나머지 내용이 어떤 사용처별 방식으로 출처를 기술하는 것이다. 그 외 경우는 함수가 문자열로 정의되었다는 뜻이고source가 그 문자열이다.
  • srclen:문자열source의 길이.
  • short_src:source의 "출력용" 버전. 오류 메시지에 사용.
  • linedefined:함수 정의가 시작하는 행 번호.
  • lastlinedefined:함수 정의가 끝나는 행 번호.
  • what:함수가 루아 함수면 문자열"Lua", C 함수면"C", 청크의 메인 부분이면"main".
  • currentline:해당 함수가 현재 실행 중인 행. 행 정보를 얻을 수 없을 때는currentline가 -1로 설정된다.
  • name:해당 함수의 적당한 이름. 루아에서 함수는 일급 값이기 때문에 고정된 이름이 없다. 어떤 함수가 여러 전역 변수의 값일 수 있고 다른 함수는 테이블 필드에만 저장되어 있을 수 있다.lua_getinfo함수에서는 그 함수가 어떻게 호출되었는지 확인해서 적절한 이름을 찾는다. 이름을 찾을 수 없으면name을NULL로 설정한다.
  • namewhat:name필드를 설명한다.namewhat의 값은 함수가 어떻게 호출되었는지에 따라서"global","local","method","field","upvalue",""(빈 문자열)일 수 있다. (어느 경우에도 해당되지 않을 때는 빈 문자열을 쓴다.)
  • istailcall:이 함수 실행이 꼬리 호출에 의한 것이면 참이다. 그 경우 스택에 이 단계의 호출자가 없다.
  • nups:함수의 upvalue 개수.
  • nparams:함수의 매개변수 개수. (C 함수에는 항상 0.)
  • isvararg:함수가 가변 인자 함수면 참이다. (C 함수에는 항상 참.)
  • ftransfer:"전송"되는 값들, 즉 호출의 매개변수나 반환 값들 중 첫 번째 값의 스택 인덱스. (나머지 값들은 이어지는 인덱스에 있다.) 이 인덱스가 있으면lua_getlocallua_setlocal을 통해 그 값들을 조회하고 변경할 수 있다. 이 필드는 호출 훅과 반환 훅에서만 의미가 있는데, 각각 첫 번째 매개변수와 반환되는 첫 번째 값을 나타낸다. (호출 훅에서 이 값은 항상 1이다.)
  • ntransfer:전송되는 값들(앞 항목 참고)의 개수. (루아 함수 호출의 경우 이 값이 항상nparams와 같다.)

lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

현재 훅 함수를 반환한다.

lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

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

lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

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

lua_getinfo

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

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

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

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

함수에 대한 정보를 얻으려면 함수를 스택에 집어넣고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이 0을 반환한다. 아니면 1을 반환한다.

lua_getupvalue

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

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

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

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

lua_Hook

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

디버그용 훅 함수 타입.

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

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

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

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

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

lua_setcstacklimit

[-0, +0, –]

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

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

lua_sethook

[-0, +0, –]

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

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

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

  • 호출 훅:인터프리터가 함수를 호출할 때 불린다. 새 함수로 진입한 직후에 함수에서 첫 번째 인자를 얻기 전에 훅을 호출한다.
  • 반환 훅:인터프리터가 함수에서 반환할 때 불린다. 함수를 떠나기 직전에 훅을 호출한다.
  • 행 훅:인터프리터가 새 코드 행 실행을 시작하려 하거나 코드에서 뒤로 (또는 같은 행으로) 점프할 때 불린다. 루아 함수 실행 중에만 이 이벤트가 발생한다.
  • 카운트 훅:인터프리터가 인스트럭션을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를 가리키게 만든다.

5 –보조 라이브러리

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

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

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

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

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

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

5.1 –함수와 타입

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

luaL_addchar

[-?, +?,m]

void luaL_addchar (luaL_Buffer *B, char c);

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

luaL_addgsub

[-0, +0,m]

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

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

luaL_addlstring

[-?, +?,m]

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

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

luaL_addsize

[-?, +?, –]

void luaL_addsize (luaL_Buffer *B, size_t n);

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

luaL_addstring

[-?, +?,m]

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

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

luaL_addvalue

[-1, +?,m]

void luaL_addvalue (luaL_Buffer *B);

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

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

luaL_argcheck

[-0, +0,v]

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

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

luaL_argerror

[-0, +0,v]

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

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

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

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

luaL_argexpected

[-0, +0,v]

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

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

luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

문자열 버퍼타입.

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

  • 먼저luaL_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_buffaddr

[-0, +0, –]

char *luaL_buffaddr (luaL_Buffer *B);

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

luaL_buffinit

[-0, +0, –]

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

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

luaL_bufflen

[-0, +0, –]

size_t luaL_bufflen (luaL_Buffer *B);

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

luaL_buffinitsize

[-?, +?,m]

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

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

luaL_buffsub

[-0, +0, –]

void luaL_buffsub (luaL_Buffer *B, int n);

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

luaL_callmeta

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

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

메타메소드를 호출한다.

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

luaL_checkany

[-0, +0,v]

void luaL_checkany (lua_State *L, int arg);

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

luaL_checkinteger

[-0, +0,v]

lua_Integer luaL_checkinteger (lua_State *L, int arg);

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

luaL_checklstring

[-0, +0,v]

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

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

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

luaL_checknumber

[-0, +0,v]

lua_Number luaL_checknumber (lua_State *L, int arg);

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

luaL_checkoption

[-0, +0,v]

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

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

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, +?,m]

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

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

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

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

luaL_dostring

[-0, +?, –]

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

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

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

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

luaL_error

[-0, +0,v]

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

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

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

luaL_execresult

[-0, +3,m]

int luaL_execresult (lua_State *L, int stat);

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

luaL_fileresult

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

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

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

luaL_getmetafield

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

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

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

luaL_getmetatable

[-0, +1,m]

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

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

luaL_getsubtable

[-0, +1,e]

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

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

luaL_gsub

[-0, +1,m]

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

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

luaL_len

[-0, +0,e]

lua_Integer luaL_len (lua_State *L, int index);

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

luaL_loadbuffer

[-0, +1, –]

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

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을 반환한다.

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

luaL_newstate

[-0, +0, –]

lua_State *luaL_newstate (void);

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

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

luaL_openlibs

[-0, +0,e]

void luaL_openlibs (lua_State *L);

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

luaL_opt

[-0, +0, –]

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

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

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

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

luaL_optinteger

[-0, +0,v]

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

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

luaL_optlstring

[-0, +0,v]

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

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

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

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

luaL_optnumber

[-0, +0,v]

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

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

luaL_optstring

[-0, +0,v]

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

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

luaL_prepbuffer

[-?, +?,m]

char *luaL_prepbuffer (luaL_Buffer *B);

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

luaL_prepbuffsize

[-?, +?,m]

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

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

luaL_pushfail

[-0, +1, –]

void luaL_pushfail (lua_State *L);

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

luaL_pushresult

[-?, +1,m]

void luaL_pushresult (luaL_Buffer *B);

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

luaL_pushresultsize

[-?, +1,m]

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

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

luaL_ref

[-1, +0,m]

int luaL_ref (lua_State *L, int t);

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

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

스택 상단의 객체가nil이면luaL_ref는 상수LUA_REFNIL을 반환한다. 상수LUA_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개 값의 사본으로 초기화한nup개 upvalue로 모든 함수들을 생성한다. 등록 후 스택에서 그 값들을 꺼낸다.

luaL_setmetatable

[-0, +0, –]

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

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

luaL_Stream

typedef struct luaL_Stream { FILE *f; lua_CFunction closef; } luaL_Stream;

표준 I/O 라이브러리에서 쓰는 파일 핸들의 표준 표현이다.

파일 핸들은LUA_FILEHANDLE이라는 메타테이블을 가진 full userdata로 구현되어 있다. (LUA_FILEHANDLE은 실제 메타테이블 이름을 나타내는 매크로다.) I/O 라이브러리에서 그 메타테이블을 만든다. (luaL_newmetatable참고.)

그 userdata는 시작 부분이luaL_Stream구조체여야 한다. 그 초반 구조 뒤에 다른 데이터를 담을 수 있다. 필드f는 대응하는 C 스트림에 대한 포인터다. (또는 생성 미완료 핸들을 나타내는NULL일 수 있다.) 필드closef는 핸들이 닫히거나 수집될 때 호출되어 스트림을 닫아 줄 루아 함수를 가리킨다. 이 함수는 파일 핸들을 유일한 인자로 받으며 성공 시 참 값을, 또는 오류 시 거짓 값과 오류 메시지를 반환해야 한다. 루아에서 이 필드를 호출한 다음 필드 값을NULL로 바꿔서 핸들이 닫혔음을 표시한다.

luaL_testudata

[-0, +0,m]

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

이 함수는luaL_checkudata처럼 동작하되, 검사 실패 시 오류를 던지는 대신NULL을 반환한다.

luaL_tolstring

[-0, +1,e]

const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

지정한 인덱스에 있는 어떤 루아 값이든 적당한 형식의 C 문자열로 변환한다. 결과 문자열을 스택에 집어넣고 반환도 한다. 또한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_typeerror

[-0, +0,v]

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

호출한 C 함수의arg번째 인자에 대한 타입 오류를 표준 메시지를 써서 던진다.tname은 기대 타입의 "이름"이다. 이 함수는 절대 반환하지 않는다.

luaL_typename

[-0, +0, –]

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

지정한 인덱스에 있는 값의 타입 이름을 반환한다.

luaL_unref

[-0, +0, –]

void luaL_unref (lua_State *L, int t, int ref);

인덱스t에 있는 테이블에서 참조ref를 해제한다. (luaL_ref참고.) 테이블에서 항목을 제거하여 피참조 객체가 수집될 수 있게 한다. 참조ref도 해제하여 다시 쓸 수 있게 한다.

ref가LUA_NOREFLUA_REFNIL이면luaL_unref가 아무것도 하지 않는다.

luaL_where

[-0, +1,m]

void luaL_where (lua_State *L, int lvl);

호출 스택lvl번 단계에서의 현재 제어 위치를 나타내는 문자열을 스택에 집어넣는다. 이 문자열은 보통 다음 형식이다.

청크이름:현재행:

0번 단계가 동작 중인 함수이고 1번 단계가 그 동작 중 함수를 호출한 함수인 식이다.

오류 메시지 시작 부분을 만드는 데 이 함수가 쓰인다.

6 –표준 라이브러리

표준 루아 라이브러리들은 C API를 통해 C로 구현된 유용한 함수들을 제공한다. 그 중 일부는 언어에 필수적인 서비스를 제공한다. (예:type,getmetatable.) 다른 일부는 외부 서비스에 접근할 수 있게 해 준다. (예: I/O.) 또 다른 일부는 루아 자체로도 구현할 수 있지만 C로 구현할 만한 다른 이유가 있었던 것들이다. (예:table.sort.)

모든 라이브러리들은 공식 C API를 통해 구현되어 있으며 별도의 C 모듈로 제공된다. 따로 언급이 없으면 이 라이브러리 함수들에선 인자 개수를 기대 매개변수 개수에 맞게 조정하지 않는다. 예를 들면foo(arg)라고 나와 있는 함수를 인자 없이 호출하지 말아야 한다.

fail표시는 어떤 실패를 나타내는 거짓 값을 뜻한다. (현재는failnil과 같지만 이후 버전에서 바뀔 수도 있다. 이 함수들의 성공 여부를 검사할 때 항상(status == nil)방식이 아니라(not status)방식을 쓰기를 권장한다.)

현재 루아에는 다음 표준 라이브러리가 있다.

  • 기본 라이브러리 (6.1절)
  • 코루틴 라이브러리 (6.2절)
  • 패키지 라이브러리 (6.3절)
  • 문자열 조작 (6.4절)
  • 기본적인 UTF-8 지원 (6.5절)
  • 테이블 조작 (6.6절)
  • 수학 함수 (6.7절) (sin, log 등)
  • 입력과 출력 (6.8절)
  • 운영 체제 기능 (6.9절)
  • 디버그 기능 (6.10절)

기본 라이브러리와 패키지 라이브러리를 제외한 다른 라이브러리들은 모든 함수를 전역 테이블의 필드나 객체의 메소드로 제공한다.

C 호스트 프로그램에서 이 라이브러리들에 접근하려면luaL_openlibs를 호출하면 된다. 그러면 모든 표준 라이브러리들을 연다. 또는 개별적으로 열기 위해 호스트 프로그램에서luaL_requiref를 사용해luaopen_base(기본 라이브러리),luaopen_package(패키지 라이브러리),luaopen_coroutine(코루틴 라이브러리),luaopen_string(문자열 라이브러리),luaopen_utf8(UTF-8 라이브러리),luaopen_table(테이블 라이브러리),luaopen_math(수학 라이브러리),luaopen_io(I/O 라이브러리),luaopen_os(운영 체제 라이브러리),luaopen_debug(디버그 라이브러리)를 부를 수 있다.lualib.h에 이 함수들이 선언되어 있다.

6.1 –기본 함수

기본 라이브러리는 루아 핵심 함수들을 제공한다. 응용에 이 라이브러리를 포함시키지 않는다면 그 요소들 중 일부를 대신하는 구현을 제공해야 하는지 여부를 조심스럽게 점검해 봐야 할 것이다.

assert (v [, message])

인자v의 값이 거짓(즉nil이나false)이면 오류를 던진다. 그렇지 않으면 인자 전체를 반환한다. 오류 경우에는message가 오류 객체가 된다. 그 인자가 없으면 "assertion failed!"를 쓴다.

collectgarbage ([opt [, arg]])

이 함수는 쓰레기 수집기에 대한 포괄적 인터페이스다. 첫 번째 인자opt에 따라서 다양한 기능을 수행한다.

  • "collect":쓰레기 수집 주기 한 번을 수행한다. 기본 옵션이다.
  • "stop":쓰레기 수집기의 자동 실행을 멈춘다. 다시 시작하기 전까지는 명시적으로 부를 때만 수집기가 돌게 된다.
  • "restart":쓰레기 수집기의 자동 실행을 다시 시작한다.
  • "count":루아에서 사용 중인 메모리의 (kB 단위) 총량을 반환한다. 값에 수소 부분이 있어서 1024로 곱하면 루아가 사용 중인 정확한 바이트 수가 나온다.
  • "step":쓰레기 수집 단계를 수행한다. 단계 "크기"를arg로 조절한다. 값이 0이면 (쪼갤 수 없는) 기본 단계 한 번을 수행한다. 값이 0이 아니면 루아가 메모리를 그만큼 (kB 단위) 할당한 것처럼 수집기가 동작을 수행한다. 그 단계로 한 수집 주기가 끝난 경우true를 반환한다.
  • "isrunning":수집기가 동작 중인지 (즉 중단되지 않았는지를) 알려 주는 불리언을 반환한다.
  • "incremental":수집기를 점진 방식으로 바꾼다. 이 옵션 뒤에 세 개의 수가 올 수 있는데, 쓰레기 수집 휴지 시간, 단계 비율, 단계 크기다. (2.5.1절참고.) 0은 값을 바꾸지 않겠다는 뜻이다.
  • "generational":수집기를 세대 방식으로 바꾼다. 이 옵션 뒤에 두 개의 수가 올 수 있는데, 쓰레기 수집 소규모 비율과 대규모 비율이다. (2.5.2절참고.) 0은 값을 바꾸지 않겠다는 뜻이다.

쓰레기 수집 동작과 일부 옵션에 대한 자세한 설명은2.5절을 보라.

dofile ([filename])

지정한 파일을 열어서 그 내용을 루아 청크로서 실행한다. 인자 없이 호출 시dofile은 표준 입력(stdin)의 내용을 실행한다. 청크가 반환한 모든 값을 반환한다. 오류 발생 시dofile은 그 오류를 호출자에게 전파한다. (즉dofile은 보호 모드로 돌지 않는다.)

error (message [, level])

@{message}를 오류 객체로 해서 오류를 던진다. (2.3절참고.) 이 함수는 절대 반환하지 않는다.

메시지가 문자열이면 일반적으로error에서 메시지 시작 부분에 오류 위치에 대한 약간의 정보를 추가한다.level인자는 그 오류 위치를 어떻게 얻을 수 있는지를 나타낸다. 단계가 1(기본값)이면error함수를 호출한 지점이 오류 위치다. 그리고 단계 2는error를 호출한 함수를 호출했던 위치를 나타내는 식이다. 단계를 0으로 주면 메시지에 오류 위치 정보를 추가하지 않는다.

_G

전역 환경(2.2절)을 가지고 있는 전역 변수다. (함수가 아니다.) 루아 자체에서는 이 변수를 쓰지 않는다. 값을 바꿔도 어느 환경에도 영향을 주지 않으며 그 반대도 마찬가지다.

getmetatable (object)

object에 메타테이블이 없으면nil을 반환한다. 그렇지 않고 객체의 메타테이블에__metatable필드가 있으면 연계된 값을 반환한다. 그 외 경우에는 지정한 객체의 메타테이블을 반환한다.

ipairs (t)

세 값(반복자 함수, 테이블t, 0)을 반환한다. 그래서 다음과 같이 쓰면

for i,v in ipairs(t) do body end

(1,t[1]), (2,t[2]), ... 식으로 해서 없는 인덱스를 만날 때까지 모든 키–값 쌍에 대해 반복하게 된다.

load (chunk [, chunkname [, mode [, env]]])

청크를 적재한다.

chunk가 문자열이면 그 문자열이 청크다.chunk가 함수면load에서 그 함수를 반복 호출해서 청크 조각들을 얻는다. 각chunk호출에서는 이전 결과들에 이어지는 문자열을 반환해야 한다. 빈 문자열 내지nil을 반환하거나 아무 값도 반환하지 않는 것으로 청크 끝을 나타낸다.

구문 오류가 없으면load는 컴파일한 청크를 함수 형태로 반환한다. 그렇지 않으면fail과 오류 메시지를 반환한다.

메인 청크를 적재할 때는 결과 함수에 항상 정확히 한 개의 upvalue, 즉_ENV변수가 있게 된다. (2.2절참고.) 하지만 함수로부터 만든 바이너리 청크를 적재할 때는 (string.dump참고) 결과 함수에 임의 개수의 upvalue가 있을 수 있으며, 첫 번째 upvalue가_ENV변수가 된다는 보장이 없다. (메인 함수가 아닌 경우에는_ENVupvalue가 없을 수도 있다.)

어떻든지 간에 결과 함수에 upvalue가 있는 경우에env매개변수가 있으면 그 값을, 아니면 전역 환경의 값을 첫 번째 upvalue에 설정한다. 다른 upvalue들은nil로 초기화한다. 모든 upvalue는 새것이다. 즉 다른 함수와 공유하지 않는다.

chunkname은 오류 메시지와 디버그 정보(4.7절)에서 청크 이름으로 쓴다. 없을 때는chunk가 문자열이면chunk를 쓰고 아니면 "=(load)"를 쓴다.

문자열mode는 청크가 텍스트나 바이너리(즉 사전 컴파일한 청크)일 수 있는지를 제어한다. 문자열 "b"(바이너리 청크만), "t"(텍스트 청크만), "bt"(바이너리와 텍스트 모두)일 수 있다. 기본은 "bt"다.

루아에서는 바이너리 청크의 무모순성을 검사하지 않는다. 악의적으로 조작된 바이너리 청크 때문에 인터프리터가 죽을 수도 있다.

loadfile ([filename [, mode [, env]]])

load와 비슷하되, 파일filename으로부터, 또는 파일 이름을 안 주면 표준 입력으로부터 청크를 얻는다.

next (table [, index])

프로그램에서 테이블의 모든 필드를 순회할 수 있게 해 준다. 첫 번째 인자는 테이블이고 두 번째 인자는 그 테이블 내의 인덱스다.next를 호출하면 테이블의 다음 인덱스와 그 연계 값을 반환한다. 두 번째 인자를nil로 해서 호출하면 시작 인덱스와 그 연계 값을 반환한다. 마지막 인덱스로 호출하거나 빈 테이블에서nil로 호출하면nil을 반환한다. 두 번째 인자가 없으면nil로 해석한다. 그래서next(t)라고 해서 테이블이 비어 있는지 확인할 수 있다.

인덱스가 나오는 순서가 명세되어 있지 않으며숫자 인덱스도 마찬가지다. (번호순으로 테이블을 순회하려면 수열형for를 쓰면 된다.)

순회 도중에 테이블에 존재하지 않던 필드에 값을 할당하는 경우next의 동작 방식이 규정되어 있지 않다. 하지만 기존 필드를 변경하는 건 괜찮다. 특히 기존 필드들을 nil로 설정할 수도 있다.

pairs (t)

t에 메타메소드__pairs가 있으면t를 인자로 해서 호출하고 그 호출의 처음 세 개 결과를 반환한다.

그렇지 않으면next함수, 테이블t,nil, 이렇게 세 값을 반환한다. 그래서 다음과 같이 쓰면

for k,v in pairs(t) do body end

테이블t의 모든 키–값 쌍에 대해 반복하게 된다.

테이블 순회 중 변경에 대한 주의 사항은 함수next를 보라.

pcall (f [, arg1, ···])

주어진 인자들을 가지고 함수f를보호 모드로 호출한다.f안에서 오류가 발생하더라도 전파되지 않는다는 뜻이다. 대신pcall이 그 오류를 잡아서 상태 코드를 반환한다. 첫 번째 결과는 상태 코드(불리언)인데 호출이 오류 없이 성공하면 참이다. 그 경우 호출의 모든 결과를pcall이 첫 번째 결과 뒤에 붙여서 반환한다. 오류 발생 시에는pcall이false와 오류 객체를 반환한다.pcall에 잡힌 오류는 메시지 핸들러를 호출하지 않는 점에 유의하라.

print (···)

임의 개수의 인자를 받아서tostring과 같은 규칙을 따라 각 인자를 문자열로 변환해서 그 값들을stdout으로 찍는다.

print함수는 서식 출력을 위한 것이 아니다. 디버깅 등을 위해 간단히 값을 표시하는 방법일 뿐이다. 출력을 완전히 제어하려면string.formatio.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)

지정한 테이블의 메타테이블을 설정한다.metatable이nil이면 지정한 테이블의 메타테이블을 제거한다. 원래 있던 메타테이블에__metatable필드가 있으면 오류를 던진다.

이 함수는table을 반환한다.

루아 코드에서 다른 타입들의 메타테이블을 바꾸려면 디버그 라이브러리(6.10절)를 사용해야 한다.

tonumber (e [, base])

base없이 호출 시tonumber는 인자를 수로 변환하려고 시도한다. 인자가 이미 수이거나 수로 변환 가능한 문자열이면 그 수를 반환한다. 그렇지 않으면fail을 반환한다.

문자열 변환 결과는 루아 어휘 규정에 따라 정수나 실수가 될 수 있다. (3.1절참고.) 문자열에 전후 공백과 부호가 있을 수 있다.

base를 주어서 호출 시e는 그 진법에서 정수로 해석되는 문자열이어야 한다. 기수로 2에서 36까지 어떤 정수도 가능하다. 10을 넘는 진법에서는 (대문자 또는 소문자) 글자 'A'가 10을 나타내고 'B'가 11을 나타내고, 그런 식으로 'Z'는 35를 나타낸다. 지정한 진법에서 문자열e가 유효한 수가 아니면 함수가fail을 반환한다.

tostring (v)

어떤 타입의 값이든 받아서 사람이 읽을 수 있는 형식의 문자열로 변환한다.

v의 메타테이블에__tostring필드가 있으면 해당 값을v를 인자로 해서 호출하여 호출 결과를tostring의 결과로 쓴다. 그렇지 않고v의 메타테이블에 문자열 값을 가진__name필드가 있으면 그 문자열을tostring의 최종 결과로 쓸 수도 있다.

수가 변환되는 방식을 완전히 제어하려면string.format을 쓰면 된다.

type (v)

인자의 타입을 문자열 형태로 반환한다. 가능한 결과는 "nil" (값nil이 아니라 문자열), "number", "string", "boolean", "table", "function", "thread", "userdata"이다.

_VERSION

동작 중인 루아 버전을 담은 문자열을 가지고 있는 전역 변수다. (함수가 아니다.) 현재 이 변수의 값은 "Lua 5.4"다.

warn (msg1, ···)

인자들(문자열이어야 함)을 모두 이어 붙여서 만든 메시지로 경고를 찍는다.

'@'로 시작하는 한 조각짜리 메시지는제어 메시지, 즉 경고 시스템 자체를 위한 메시지인 것으로 약속되어 있다. 특히 루아의 표준 경고 함수에서는 경고 찍기를 멈추는 "@off"와 찍기를 (재)시작하는 "@on"을 인식한다. 모르는 제어 메시지는 무시한다.

xpcall (f, msgh [, arg1, ···])

이 함수는pcall과 비슷하되, 새 메시지 핸들러msgh를 설정한다.

6.2 –코루틴 조작

이 라이브러리는 코루틴을 조작하는 동작들로 이뤄져 있으며 테이블coroutine안에 들어 있다. 코루틴에 대한 일반적 설명은2.6절을 보라.

coroutine.close (co)

코루틴co를 닫는다. 즉 미처리 자동 닫힘 변수를 모두 닫고 코루틴을 죽은 상태로 만든다. 지정한 코루틴은 죽어 있거나 정지 상태여야 한다. 변수를 닫는 중 오류가 발생하면false와 오류 객체를 반환한다. 아니면true를 반환한다.

coroutine.create (f)

f를 몸체로 해서 새 코루틴을 만든다.f는 함수여야 한다."thread"타입 객체인 새 코루틴을 반환한다.

coroutine.isyieldable ([co])

코루틴co가 양보할 수 있으면 참을 반환한다.co의 기본값은 동작 중인 코루틴이다.

코루틴이 양보할 수 있으려면 메인 스레드가 아니고 양보 불가능한 C 함수 안에 있지 않으면 된다.

coroutine.resume (co [, val1, ···])

코루틴co의 실행을 시작하거나 이어 나간다. 코루틴을 처음 재개할 때 그 몸체 실행을 시작한다.val1, ... 값들이 몸체 함수에게 인자로 전달된다. 코루틴이 양보를 하고 난 후에resume하면 코루틴을 재시작한다.val1, ... 값들이 yield의 결과로 전달된다.

코루틴이 오류 없이 돌면true에 더해서 (코루틴이 양보할 때)yield로 전달된 값들이나 (코루틴이 끝날 때) 몸체 함수가 반환한 값들을resume이 반환한다. 오류가 있으면false와 오류 메시지를 반환한다.

coroutine.running ()

동작 중인 코루틴에 더해서 불리언을 반환하는데, 동작 중인 코루틴이 메인 코루틴일 때 참이다.

coroutine.status (co)

코루틴co의 상태를 문자열로 반환한다. 코루틴이 동작 중이면 (즉status를 호출한 바로 그 코루틴이면)"running"이고, 코루틴이yield호출 내에서 정지되어 있거나 아직 동작을 시작하지 않았으면"suspended"고, 코루틴이 활성이지만 동작 중이 아니면 (즉 다른 코루틴을 재개했으면)"normal"이고, 코루틴이 몸체 함수를 끝마쳤거나 오류로 중단되었으면"dead"다.

coroutine.wrap (f)

f를 몸체로 해서 새 코루틴을 만든다.f는 함수여야 한다. 함수를 반환하는데, 그 함수를 호출할 때마다 코루틴을 재개한다. 그 함수에 인자를 주면resume에 준 추가 인자처럼 동작한다. 그리고 처음의 불리언을 빼고resume이 반환하는 것과 같은 값들을 반환한다. 오류 발생 시 함수에서 코루틴을 닫고 오류를 전파한다.

coroutine.yield (···)

호출한 코루틴의 실행을 정지한다.yield에 인자를 주면resume의 추가 결과로 전달된다.

6.3 –모듈

패키지 라이브러리는 루아에서 모듈을 적재하기 위한 기본 요소들을 제공한다. 전역 환경으로 직접 내보내는 함수는require하나다. 나머지는 모두 테이블package를 통해 내보낸다.

require (modname)

지정한 모듈을 적재한다. 먼저package.loaded테이블을 확인해서modname이 이미 적재되어 있는지 알아본다. 그 경우에는package.loaded[modname]에 저장된 값을require가 반환한다. (이 경우 두 번째 결과가 없다는 점이 모듈을 적재할 필요가 없었다는 것을 나타낸다.) 아닌 경우에는 그 모듈을 위한적재 함수를 찾아 본다.

require에서 적재 함수를 찾는 동작은package.searchers테이블에 따라 이뤄진다. 이 테이블의 각 항목은 특정 방식으로 모듈을 찾는 탐색 함수다. 이 테이블을 바꾸면require에서 모듈을 찾는 방식을 바꿀 수 있다. 다음 설명은package.searchers의 기본 설정을 기준으로 한 것이다.

require에서 먼저package.preload[modname]을 확인한다. 값이 있으면 (함수여야 하는) 그 값이 적재 함수다. 그렇지 않으면package.path에 저장된 경로를 이용해 루아 적재 함수를 탐색한다. 그것도 실패하면package.cpath에 저장된 경로를 이용해 C 적재 함수를 탐색한다. 그것도 실패하면일체형적재 함수를 시도한다. (package.searchers참고.)

적재 함수를 찾으면modname, 그리고 탐색 함수가 반환한 추가 값인적재 데이터를 인자로 해서require에서 적재 함수를 호출한다. 모듈에 유용한 어떤 값이든 적재 데이터가 될 수 있다. 기본 탐색 함수들에서 적재 데이터는 어디서 적재 함수를 찾았는지 나타낸다. (예를 들어 적재 함수가 파일에서 왔다면 그 추가 값은 파일 이름이다.) 적재 함수가 nil 아닌 값을 반환하면require에서 그 반환 값을package.loaded[modname]에 할당한다. 적재 함수가 nil 아닌 값을 반환하지 않고package.loaded[modname]에 어떤 값도 할당하지 않았으면require에서 그 항목에true를 할당한다. 어느 경우든package.loaded[modname]의 최종 값을require가 반환한다. 그 값에 더해서 탐색 함수가 반환한 적재 데이터를 두 번째 결과로 반환하는데, 그 값은require가 모듈을 어떻게 찾았는지를 나타낸다.

모듈 적재나 실행 중 오류가 있거나 모듈 적재 함수를 찾을 수 없는 경우에는require가 오류를 던진다.

package.config

패키지의 컴파일 시점 설정들을 기술하는 문자열. 이 문자열은 다음 행들이 차례로 이어진 것이다.

  • 첫 번째 행은 디렉터리 구분 문자열이다. 기본값은 윈도우에서 '\'이고 다른 모든 시스템에서 '/'이다.
  • 두 번째 행은 경로 내에서 템플릿을 구분하는 문자이다. 기본값은 ';'이다.
  • 세 번째 행은 템플릿 내에서 치환 지점을 표시하는 문자열이다. 기본값은 '?'이다.
  • 네 번째 행은 윈도우 경로에서 실행 파일의 디렉터리로 바뀌는 문자열이다. 기본값은 '!'이다.
  • 다섯 번째 행은luaopen_함수 이름을 만들어 낼 때 이후 텍스트를 모두 무시하게 하는 표시다. 기본값은 '-'이다.

package.cpath

require에서 C 적재 함수 탐색에 쓰는 경로를 담은 문자열.

루아 경로package.path와 같은 방식으로 C 경로package.cpath를 초기화한다. 환경 변수LUA_CPATH_5_4나 환경 변수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_4나 환경 변수LUA_PATH의 값으로 초기화한다. 그 환경 변수들이 정의되어 있지 않으면luaconf.h에 정의된 기본 경로로 초기화한다. 환경 변수 값 내에 ";;"가 있으면 기본 경로로 바뀐다.

package.preload

개별 모듈을 위한 적재 함수들을 저장하는 테이블. (require참고.)

이 변수는 실제 테이블에 대한 참조일 뿐이다. 이 변수에 할당을 해도require에서 쓰는 테이블은 바뀌지 않는다.

package.searchers

모듈을 찾는 방식을 제어하기 위해require에서 쓰는 테이블.

이 테이블의 각 항목은탐색 함수다. 모듈을 찾을 때require에서 이 탐색 함수 각각을 오름차순으로, 모듈 이름(require가 받은 인자)을 유일한 인자로 해서 호출한다. 탐색 함수에서 모듈을 찾으면 또 다른 함수인 모듈적재 함수와 함께적재 데이터를 추가로 반환하는데, 그 값이 적재 함수로 전달되고require의 두 번째 결과로 반환된다. 모듈을 찾을 수 없으면 이유를 설명하는 문자열을 (설명할 게 없으면nil을) 반환한다.

루아에서 네 가지 탐색 함수로 이 테이블을 초기화한다.

첫 번째 탐색 함수는package.preload테이블 안의 적재 함수를 찾아 보기만 한다.

두 번째 탐색 함수는package.path에 저장된 경로를 이용해 루아 라이브러리 적재 함수를 찾는다. 함수package.searchpath에 기술한 대로 탐색이 이뤄진다.

세 번째 탐색 함수는 변수package.cpath에서 얻은 경로를 이용해 C 라이브러리 적재 함수를 찾는다. 마찬가지로 함수package.searchpath에 기술한 대로 탐색이 이뤄진다. 예를 들어 C 경로가 다음 문자열일 때

"./?.so;./?.dll;/usr/local/?/init.so"

모듈foo탐색 함수는 파일./foo.so,./foo.dll,/usr/local/foo/init.so를 차례대로 열어 보게 된다. 탐색 함수에서 C 라이브러리를 찾으면 먼저 동적 링크 기능을 이용해 응용을 그 라이브러리와 링크한다. 그러고 나서 적재 함수로 사용할 C 함수를 그 라이브러리 안에서 찾아 본다. 그 C 함수의 이름은 문자열 "luaopen_"에 모듈 이름 사본을 덧붙이고서 마침표를 밑줄로 바꾼 것이다. 그리고 모듈 이름에 하이픈이 있으면 첫 번째 하이픈과 이후 내용을 제거한다. 예를 들어 모듈 이름이a.b.c-v2.1이면 함수 이름이luaopen_a_b_c가 된다.

네 번째 탐색 함수는일체형 적재 함수를 시도한다. 지정한 모듈의 최상위 단계 이름으로 라이브러리의 C 경로를 탐색한다. 예를 들어a.b.c를 요청한 경우a의 C 라이브러리를 찾게 된다. 발견하면 그 안에서 서브모듈의 열기 함수를 찾는다. 예컨대luaopen_a_b_c를 찾게 된다. 이 기능을 이용하면 패키지에서 라이브러리 한 개에 여러 C 서브모듈을 집어넣으면서 각 서브모듈의 열기 함수를 그대로 쓸 수 있다.

첫 번째(preload)를 제외한 모든 탐색 함수는package.searchpath가 반환한 모듈 발견 파일 경로를 추가 값으로 반환한다. 첫 번째 탐색 함수는 항상 문자열 ":preload:"를 반환한다.

탐색 함수에선 오류를 던지지 말아야 하고 루아에 어떤 부작용도 끼쳐선 안 된다. (C에는 예를 들어 응용을 라이브러리와 링크하면서 부작용을 끼칠 수도 있다.)

package.searchpath (name, path [, sep [, rep]])

지정한path에서 지정한name을 찾는다.

path는템플릿들을 세미콜론으로 구분해 담은 문자열이다. 각 템플릿에 대해서 물음표가 들어 있으면sep(기본값은 마침표)를 모두rep(기본값은 시스템의 디렉터리 구분자)로 바꾼name의 사본으로 치환하고서 결과로 나온 파일 이름으로 열기를 시도한다.

예를 들어path가 다음 문자열인 경우에

"./?.lua;./?.lc;/usr/local/?/init.lua"

이름을foo.a로 해서 탐색하면 파일./foo/a.lua,./foo/a.lc,/usr/local/foo/a/init.lua를 차례대로 열어 보게 된다.

읽기 모드로 열 수 있는 첫 번째 파일의 치환 후 이름을 (파일을 닫고서) 반환한다. 성공한 파일이 없으면fail과 오류 메시지를 반환한다. (그 오류 메시지에는 열기를 시도한 모든 파일 이름이 나열되어 있다.)

6.4 –문자열 조작

이 라이브러리는 부분 문자열 검색과 추출, 패턴 검사 같은 문자열 조작을 위한 일반적 함수들을 제공한다. 루아에서 문자열에 인덱스를 쓸 때는 첫 번째 글자가 1번 위치다. (C에서처럼 0번이 아니다.) 인덱스가 음수일 수도 있으며 문자열 끝을 기준으로 한 역방향 인덱스로 해석한다. 즉 마지막 문자가 -1번 위치에 있는 식이다.

문자열 라이브러리는 모든 함수를 테이블string에 담아서 제공한다. 그리고 문자열에 대한 메타테이블을 설정하는데 거기서__index필드가string테이블을 가리킨다. 그래서 문자열 함수들을 객체 지향 스타일로 사용할 수 있다. 예를 들어string.byte(s,i)를s:byte(i)라고 쓸 수 있다.

문자열 라이브러리에서는 1바이트 문자 인코딩을 상정한다.

string.byte (s [, i [, j]])

문자s[i],s[i+1], ...,s[j]의 내부용 수 코드들을 반환한다.i의 기본값은 1이고j의 기본값은i이다.string.sub함수와 같은 규칙에 따라서 인덱스들을 정정한다.

수 코드가 반드시 플랫폼 간에 이식성이 있지는 않다.

string.char (···)

0개 이상의 정수를 받아서 길이가 인자 개수와 같은 문자열을 반환한다. 문자열 각 문자의 내부용 수 코드가 대응하는 인자와 같다.

수 코드가 반드시 플랫폼 간에 이식성이 있지는 않다.

string.dump (function [, strip])

주어진 함수의 이진 표현(바이너리 청크)을 담은 문자열을 반환한다. 이후 그 문자열에load하면 함수의 복사본을 (새 upvalue로) 반환한다.strip이 참 값이면 공간 절약을 위해 이진 표현에 함수에 대한 디버그 정보가 포함되지 않을 수도 있다.

upvalue가 있는 함수인 경우 upvalue 개수만 저장된다. (재)적재 때 그 upvalue들이 새 인스턴스를 받는다. (그 upvalue들이 초기화되는 방식에 대한 자세한 내용은load를 보라. 디버그 라이브러리를 이용하면 원하는 방식으로 함수의 upvalue를 직렬화 및 재적재할 수 있다.)

string.find (s, pattern [, init [, plain]])

문자열s에서pattern의 첫 번째 일치 위치를 찾는다. (6.4.1절참고.) 일치하는 부분을 발견하면 시작점과 끝점의s내 인덱스를 반환한다. 못 찾으면fail을 반환한다. 세 번째의 선택적 수 인자init은 탐색을 시작할 위치를 지정한다. 기본값은 1이며 음수일 수 있다. 네 번째의 선택적 인자plain에true값을 주면 패턴 검사 기능을 끈다. 그래서pattern내의 어떤 문자도 특수하게 취급하지 않고 단순한 "부분 문자열 찾기" 동작을 한다.

패턴에 포획이 있으면 일치 성공 시 두 인덱스 뒤에 잡힌 값들을 함께 반환한다.

string.format (formatstring, ···)

문자열이어야 하는 첫 번째 인자에 따라서 가변 개수 인자들로 만든 서식 적용 문자열을 반환한다. 서식 문자열은 ISO C 함수sprintf와 같은 규칙을 따른다. 다만 변환 지정자 및 수식자*,h,L,l,n을 지원하지 않으며 추가로 지정자q가 있다.

지정자q는 불리언, nil, 수, 문자열을 루아 소스 코드에서 유효한 상수가 되는 방식으로 변환해 준다. 불리언과 nil은 자명한 방식으로 (true,false,nil) 바꾼다. 실수는 16진수로 표현해서 정밀도를 온전히 유지한다. 문자열은 큰따옴표 안에 넣으며 필요하면 이스케이프 열을 써서 그 결과를 루아 인터프리터가 안전하게 읽을 수 있도록 한다. 예를 들어 다음과 같이 호출하면

string.format('%q', 'a string with "quotes" and \n new line')

다음 문자열이 나온다.

"a string with \"quotes\" and \ new line"

이 지정자는 수식자(플래그, 폭, 길이)를 지원하지 않는다.

변환 지정자A,a,E,e,f,G,g는 모두 인자로 수를 기대한다. 지정자c,d,i,o,u,X,x는 정수를 기대한다. C89 컴파일러로 루아를 컴파일하는 경우에는 지정자A와a(16진법 실수)는 수식자를 지원하지 않는다.

지정자s는 문자열을 기대한다. 인자가 문자열이 아니면tostring과 같은 규칙에 따라 문자열로 변환한다. 지정자에 수식자가 있는 경우에는 대응하는 문자열 인자에 0이 포함돼 있지 않아야 한다.

지정자p는lua_topointer가 반환한 포인터를 받는다. 테이블, userdata, 스레드, 문자열, 함수에 대해 유일한 문자열 식별자를 만들어 준다. 다른 값들(수, nil, 불리언)에 대해 이 지정자는 포인터NULL을 나타내는 문자열을 내놓는다.

string.gmatch (s, pattern [, init])

반복자 함수를 반환한다. 호출할 때마다 그 함수는 문자열s에 대한pattern의 다음 포획 값들을 반환한다. (6.4.1절참고.)pattern에 포획을 지정하지 않으면 각 호출마다 일치 부분 전체를 내놓는다. 세 번째의 선택적 수 인자init은 탐색을 시작할 위치를 지정한다. 기본값은 1이며 음수일 수 있다.

예를 들어 다음 루프는 문자열s의 단어를 모두 돌면서 한 줄에 한 단어씩 찍는다.

s = "hello world from Lua" for w in string.gmatch(s, "%a+") do print(w) end

다음 예는 주어진 문자열에서key=value쌍을 모두 모아서 테이블에 넣는다.

t = {} s = "from=world, to=Lua" for k, v in string.gmatch(s, "(%w+)=(%w+)") do t[k] = v end

이 함수에서는 패턴 시작의 '^'가 앵커 역할을 하지 않는다. 그러면 반복이 불가능해지기 때문이다.

string.gsub (s, pattern, repl [, n])

s에서 모든 (또는 지정한 경우 처음n개)pattern을 치환 문자열repl로 바꾼 사본을 반환한다. (6.4.1절참고.)repl은 문자열, 테이블, 함수일 수 있다. 또한gsub는 두 번째 값으로 치환 횟수를 반환한다.gsub라는 이름은Global SUBstitution(전역 치환)에서 온 것이다.

repl이 문자열이면 그 값을 치환에 쓴다. 문자%는 이스케이프 문자 기능을 하는데,repl내에%d형태의 열이 있으면 (d는 1에서 9 사이)d번째로 잡힌 부분 문자열의 값을 나타낸다.%0은 일치하는 부분 전체를 나타내고%%은%한 개를 나타낸다.

repl이 테이블이면 일치가 있을 때마다 첫 번째 포획 값을 키로 해서 테이블에 질의한다.

repl이 함수면 일치가 있을 때마다 포획된 부분 문자열 모두를 순서대로 인자로 해서 그 함수를 호출한다.

어느 경우든 패턴에 포획을 지정하지 않으면 패턴 전체가 포획 안에 있는 것처럼 동작한다.

테이블 질의나 함수 호출의 반환 값이 문자열이나 수이면 치환 문자열로 쓴다. 그렇지 않고falsenil이면 교체하지 않는 것이다. (즉 문자열 내의 그 일치 부분을 그대로 유지한다.)

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

x = string.gsub("hello world", "(%w+)", "%1 %1") --> x="hello hello world world" x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello world" x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") --> x="world hello Lua from" x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) --> x="home = /home/roberto, user = roberto" x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return load(s)() end) --> x="4+5 = 9" local t = {name="lua", version="5.4"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.4.tar.gz"

string.len (s)

문자열을 받아서 그 길이를 반환한다. 빈 문자열""의 길이는 0이다. 문자열 내의 0도 산입된다. 따라서"a\000bc\000"의 길이가 5다.

string.lower (s)

문자열을 받아서 대문자 글자가 모두 소문자로 바뀐 사본을 반환한다. 다른 글자들은 바뀌지 않는다. 무엇이 대문자 글자인지에 대한 정의는 현재 로캘에 따라 정해진다.

string.match (s, pattern [, init])

문자열s에서pattern의 첫 번째일치 부분을 찾는다. (6.4.1절참고.) 일치 부분을 발견하면 패턴의 포획 값들을 반환한다. 못 찾았으면fail을 반환한다.pattern에 포획을 지정하지 않으면 일치 부분 전체를 반환한다. 세 번째의 선택적 수 인자init은 탐색을 시작할 위치를 지정한다. 기본값이 1이며 음수일 수 있다.

string.pack (fmt, v1, v2, ···)

값v1,v2등을 형식 문자열fmt에 따라 이진 형태로 직렬화한 (포장한) 이진 문자열을 반환한다. (6.4.2절참고.)

string.packsize (fmt)

지정한 형식으로string.pack하면 나오는 문자열의 크기를 반환한다. 형식 문자열에 가변 길이 옵션인 's'나 'z'가 있을 수 없다. (6.4.2절참고.)

string.rep (s, n [, sep])

문자열s의 사본n개를 문자열sep를 구분자로 해서 이어 붙인 문자열을 반환한다.sep의 기본값은 빈 문자열(즉 구분자 없음)이다.n이 양수가 아니면 빈 문자열을 반환한다.

(이 함수 호출 한 번으로 머신의 메모리를 아주 쉽게 고갈시킬 수 있다는 점에 유의하라.)

string.reverse (s)

문자열s를 뒤집은 문자열을 반환한다.

string.sub (s, i [, j])

i에서 시작해서j까지 이어지는s의 부분 문자열을 반환한다.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)

문자열을 받아서 소문자 글자가 모두 대문자로 바뀐 사본을 반환한다. 다른 글자들은 바뀌지 않는다. 무엇이 소문자 글자인지에 대한 정의는 현재 로캘에 따라 정해진다.

6.4.1 –패턴

루아에서는 정규 문자열로 패턴을 기술한다. 패턴 검사 함수string.find,string.gmatch,string.gsub,string.match에서 정규 문자열을 패턴으로 해석한다. 이 절에서는 그 문자열의 문법과 의미(즉 무엇에 일치하는지)를 설명한다.

문자 클래스:

문자 클래스를 사용해 문자들의 집합을 나타낸다. 다음 요소들로 문자 클래스를 기술할 수 있다.

  • x:(x가특수 문자^$()%.[]*+-?중 하나가 아님) 문자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.gsub와 반복자string.gmatch는 지정한 패턴으로 대상에서 여러 번 일치 부분을 찾는다. 그 함수들에서는 이전 일치 부분의 끝에서 최소 한 바이트 뒤에서 끝나는 경우에만 새 일치 부분이 유효하다고 본다. 달리 말해 패턴 머신에서 어떤 일치 부분 바로 다음의 빈 문자열을 일치 부분으로 받아들이지 않는다. 예를 들어 다음 코드의 결과를 생각해 보자.

> string.gsub("abc", "()a*()", print); --> 1 2 --> 3 3 --> 4 4

두 번째와 세 번째 결과는 'b' 다음의 빈 문자열과 'c' 다음의 빈 문자열이 걸려서 나온 것이다. 'a' 다음의 빈 문자열은 걸리지 않는데, 이전 일치 부분과 같은 위치에서 끝나게 되기 때문이다.

6.4.2 –포장 형식 문자열

string.pack,string.packsize,string.unpack의 첫 번째 인자는 만들거나 읽으려는 구조체의 레이아웃을 기술하는 형식 문자열이다.

형식 문자열은 일련의 변환 옵션들이다. 가능한 변환 옵션은 다음과 같다.

  • <:리틀 엔디안 설정
  • >:빅 엔디안 설정
  • =:시스템 기본 엔디안 설정
  • ![n]:최대 정렬 크기를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에서 무시한다.

6.5 –UTF-8 지원

이 라이브러리는 기초적인 UTF-8 인코딩 지원을 제공한다. 모든 함수를 테이블utf8에 담아서 제공한다. 인코딩 처리 외의 유니코드 지원은 제공하지 않는다. 문자 분류처럼 문자의 의미가 필요한 동작은 지원 범위에 포함되지 않는다.

따로 명시하지 않았으면 바이트 위치를 매개변수로 받는 함수에서는 받은 위치가 바이트 열의 시작이거나 아니면 대상 문자열 길이 더하기 1이라고 상정한다. 문자열 라이브러리에서처럼 음수 인덱스는 문자열 끝부터 거꾸로 센다.

바이트 열을 만들어 내는 함수들은 원래 UTF-8 명세에 정의된 대로0x7FFFFFFF까지의 모든 값을 받는다. 즉 여섯 바이트까지의 바이트 열이 나올 수 있다.

바이트 열을 해석하는 함수들은 유효한 (올바른 형식이고 과잉 길이가 아닌) 열만 받아들인다. 기본적으로 유효한 유니코드 코드 포인트가 나오는 바이트 열만 받으며10FFFF보다 큰 값과 서러게이트는 거부한다. 불리언 인자lax가 있는 경우 이를 가지고 검사를 완화해서0x7FFFFFFF까지의 모든 값을 받아들이게 할 수 있다. (형식이 올바르지 않거나 과잉 길이인 열은 여전히 거부된다.)

utf8.char (···)

0개 이상의 정수를 받아서 각각을 대응하는 UTF-8 바이트 열로 변환하고 그 열들을 모두 이어 붙인 문자열을 반환한다.

utf8.charpattern

패턴 (즉 함수가 아니라 문자열) "[\0-\x7F\xC2-\xF4][\x80-0xBF]*"다. (6.4.1절참고.) 대상이 유효한 UTF-8 문자열이라고 하면 정확히 한 개의 UTF-8 바이트 열에 일치한다.

utf8.codes (s [, lax])

다음과 같이 쓰면

for p, c in utf8.codes(s) do body end

문자열s의 모든 UTF-8 문자에 대해 반복하도록 값을 반환한다. 각 문자에서p는 (바이트 단위) 위치이고c는 코드 포인트다. 유효하지 않은 바이트 열을 만나면 오류를 던진다.

utf8.codepoint (s [, i [, j [, lax]]])

s에서 바이트 위치i와j사이에서 (두 위치 포함) 시작하는 모든 문자들의 코드 포인트를 (정수로) 반환한다.i의 기본값은 1이고j의 기본값은i다. 유효하지 않은 바이트 열을 만나면 오류를 던진다.

utf8.len (s [, i [, j [, lax]]])

문자열s에서 위치i와j사이에서 (두 위치 포함) 시작하는 UTF-8 문자들의 수를 반환한다.i의 기본값은 1이고j의 기본값은 -1이다. 유효하지 않은 바이트 열을 발견하면fail과 첫 번째 비유효 바이트의 위치를 반환한다.

utf8.offset (s, n [, i])

s에서 (위치i부터 세어서)n번째 문자의 인코딩이 시작되는 (바이트 단위) 위치를 반환한다.n이 음수면i번 위치 앞의 문자를 뜻한다.i의 기본값은n이 음수가 아니면 1이고, 음수면#s + 1이다. 그래서utf8.offset(s, -n)이라고 하면 문자열 끝에서n번째 문자의 오프셋을 얻게 된다. 지정한 문자가 대상 문자열 안이나 끝 바로 다음에 있지 않으면fail을 반환한다.

특별히n이 0일 때는s의i번째 바이트를 포함하는 문자의 인코딩 시작점을 반환한다.

이 함수에서는s가 유효한 UTF-8 문자열이라고 가정한다.

6.6 –테이블 조작

이 라이브러리는 테이블 조작을 위한 일반적 함수들을 제공한다. 모든 함수를 테이블table에 담아서 제공한다.

동작에 테이블 길이가 필요한 경우마다 길이 연산자에 대한 주의 사항이 모두 적용된다. (3.4.7절참고.) 모든 함수에서 인자로 받은 테이블의 수 아닌 키는 무시한다.

table.concat (list [, sep [, i [, j]]])

모든 항목이 문자열이나 수인 리스트를 받아서 문자열list[i]..sep..list[i+1] ··· sep..list[j]를 반환한다.sep의 기본값은 빈 문자열이고,i의 기본값은 1이며,j의 기본값은#list다.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"에 인자 총개수를 넣은 새 테이블을 반환한다. 참고로 일부 인자가nil이면 결과로 나오는 테이블이 열이 아닐 수도 있다.

table.remove (list [, pos])

list에서pos위치에 있는 항목을 제거하고 그 값을 반환한다.pos가 1과#list사이의 정수면 항목list[pos+1], list[pos+2], ···, list[#list]를 앞으로 밀어서 항목list[#list]를 없앤다.#list가 0일 때는pos가 0일 수 있고#list + 1일 수도 있다.

pos의 기본값이#list다. 그래서table.remove(l)호출이 리스트l의 마지막 항목을 제거한다.

table.sort (list [, comp])

list[1]부터list[#list]까지 리스트 항목들을 지정한 순서로제자리에서정렬한다.comp는 있다면 리스트의 항목 두 개를 받는 함수여야 하는데, 첫 번째 항목이 최종 순서에서 두 번째 항목보다 앞에 가야 할 때 참을 반환한다. (즉 정렬 후에i < j이면not comp(list[j],list[i])여야 한다.)comp가 없으면 표준 루아 연산자<를 대신 쓴다.

참고로comp함수가 리스트 내 항목들에 대한 순부분 순서를 정의해야 한다. 즉, 비대칭성과 추이성이 있어야 한다. 안 그러면 어떤 유효한 정렬도 가능하지 않다.

정렬 알고리즘이 안정적이지 않다. 즉, 해당하는 순서에서 같다고 보는 항목들의 상대적 위치가 정렬에 의해 바뀔 수도 있다.

table.unpack (list [, i [, j]])

받은 리스트의 항목들을 반환한다. 이 함수는 다음과 동등하다.

return list[i], list[i+1], ···, list[j]

i의 기본값은 1이고j는#list다.

6.7 –수학 함수

이 라이브러리는 기초적인 수학 함수들을 제공한다. 모든 함수와 상수를 테이블math에 담아서 제공한다. "정수/실수"라고 표기한 함수는 정수 인자에 대해 정수 결과를 내놓고 정수 아닌 인자에 대해 실수 결과를 내놓는다. 올림/내림 함수math.ceil,math.floor,math.modf는 결과가 정수 범위에 들어가면 정수를 반환하고 아니면 실수를 반환한다.

math.abs (x)

x와-x중 큰 값을 반환한다. (정수/실수)

math.acos (x)

x의 아크코사인을 반환한다. (라디안)

math.asin (x)

x의 아크사인을 반환한다. (라디안)

math.atan (y [, x])

y/x의 아크탄젠트를 반환하되 (라디안), 두 인자의 부호를 이용해 결과 값의 사분면을 알아낸다.x가 0인 경우도 올바로 처리한다.

x의 기본값은 1이다. 그래서math.atan(y)호출이y의 아크탄젠트를 반환한다.

math.ceil (x)

x보다 크거나 같은 가장 작은 정수 값을 반환한다.

math.cos (x)

x의 코사인을 반환한다. (라디안)

math.deg (x)

각도x를 라디안에서 도 단위로 변환한다.

math.exp (x)

ex값을 반환한다. (e는 자연로그의 밑이다.)

math.floor (x)

x보다 작거나 같은 가장 큰 정수 값을 반환한다.

math.fmod (x, y)

몫을 0을 향해 내림/올림하는 방식으로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에 대해math.random(n)호출은math.random(1,n)과 동등하다.math.random(0)호출은 모든 비트가 유사 난수인 정수를 내놓는다.

xoshiro256**알고리즘을 써서 유사 난수인 64비트 정수를 만들어 내고, 그 값이 인자 0인 호출의 결과가 된다. 다른 결과들(범위 및 실수)은 그 정수들에서 편향 없이 추출한 값이다.

루아에서는 인자 없는math.randomseed호출과 동등한 방식으로 유사 난수 생성기를 초기화한다. 따라서 프로그램이 실행될 때마다math.random이 만들어 내는 결과 수열이 달라지게 된다.

math.randomseed ([x [, y]])

인자를 적어도 한 개 줘서 호출하면 정수 매개변수x와y를 합쳐 128비트시드로 만들어서 유사 난수 생성기를 다시 초기화하는 데 쓴다. 시드가 같으면 만들어 내는 수열이 같다.y의 기본값은 0이다.

인자 없이 호출하면 약한 수준의 난수성으로 시드를 생성한다.

이 함수는 실제 사용한 두 시드 요소를 반환한다. 그 값들을 다시 설정하면 수열이 반복된다.

초기 상태에 적절한 수준의 난수성을 주려면 (또는 반대로 가령 프로그램 디버깅 시 정해진 수열이 나오게 하려면) 명시적 인자로math.randomseed를 호출해 주어야 한다.

math.sin (x)

x의 사인을 반환한다. (라디안)

math.sqrt (x)

x의 제곱근을 반환한다. (식x^0.5로도 이 값을 계산할 수 있다.)

math.tan (x)

x의 탄젠트를 반환한다. (라디안)

math.tointeger (x)

값x가 정수로 변환 가능하면 그 정수를 반환한다. 그렇지 않으면fail을 반환한다.

math.type (x)

x가 정수면 "integer"를 반환하고, 실수면 "float"을 반환하고,x가 수가 아니면fail을 반환한다.

math.ult (m, n)

불리언을 반환한다. 부호 없는 정수로 비교할 때 정수m이 정수n보다 작으면, 그리고 그 경우에만 참이다.

6.8 –입출력 기능

I/O 라이브러리에서는 두 가지 파일 조작 방식을 제공한다. 첫 번째는 암묵적 파일 핸들을 사용하는 것이다. 즉, 기본 입력 파일과 기본 출력 파일을 설정하는 동작이 있고 모든 입출력 동작이 그 기본 파일에서 이뤄진다. 두 번째 방식은 명시적인 파일 핸들을 쓰는 것이다.

암묵적 파일 핸들을 쓸 때는 모든 동작이 테이블io에 담겨서 제공된다. 명시적 파일 핸들을 쓸 때는io.open동작이 파일 핸들을 반환하고 그 파일 핸들의 메소드 형태로 모든 동작이 제공된다.

파일 핸들의 메타테이블에 있는 메타메소드__gc와__close는 호출 시 파일 닫기를 시도한다.

테이블io에는 또한 미리 정의된 파일 핸들io.stdin,io.stdout,io.stderr가 있는데, 그 의미는 C에서와 같다. I/O 라이브러리에서는 이 파일들을 절대 닫지 않는다.

따로 명시하지 않았으면 모든 I/O 함수는 실패 시fail, 그리고 두 번째 결과로 오류 메시지와 세 번째 결과로 시스템별 오류 코드를 반환한다. 성공 시에는 어떤 거짓 아닌 값을 반환한다. 오류 발생 시 오류 메시지와 오류 코드 계산에 전역 C 변수errno를 이용하기 때문에 POSIX를 준수하지 않는 시스템에서는 스레드에 안전하지 않을 수 있다.

io.close ([file])

file:close()와 동등하다.file이 없으면 기본 출력 파일을 닫는다.

io.flush ()

io.output():flush()와 동등하다.

io.input ([file])

파일 이름으로 호출하면 그 파일을 (텍스트 모드로) 열어서 그 핸들을 기본 입력 파일로 설정한다. 파일 핸들로 호출하면 그 파일 핸들을 기본 입력 파일로 설정하기만 한다. 인자 없이 호출하면 현재의 기본 입력 파일을 반환한다.

오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.

io.lines ([filename, ···])

지정한 파일 이름을 읽기 모드로 열어서 반복자 함수를 반환한다. 그 함수는 열린 파일의file:lines(···)처럼 동작한다. 반복자 함수는 아무 값이라도 읽기에 실패하면 자동으로 파일을 닫는다.io.lines는 반복자 말고도 세 개 값을 더 반환하는데, 자리를 채우기 위한nil값 두 개와 새로 생긴 파일 핸들이다. 따라서 일반형for루프에 사용 시 오류나break로 루프가 중단될 때도 파일이 닫힌다.

(파일 이름 없는)io.lines()호출은io.input():lines("l")와 동등하다. 즉, 기본 입력 파일의 행들에 대해 반복한다. 이 경우에는 루프가 끝날 때 반복자가 파일을 닫지 않는다.

파일 여는 중 오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.

io.open (filename [, mode])

문자열mode에 지정한 방식으로 파일을 연다. 성공 시 새 파일 핸들을 반환한다.

mode문자열은 다음 중 하나일 수 있다.

  • "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가 파일 핸들이 아니면fail을 반환한다.

io.write (···)

io.output():write(···)와 동등하다.

file:close ()

file을 닫는다. 참고로 파일 핸들이 쓰레기로 수집될 때 파일이 자동으로 닫힌다. 하지만 얼마나 지나서 그렇게 될지 예측할 수 없다.

io.popen으로 만든 파일 핸들을 닫을 때file:closeos.execute와 같은 값들을 반환한다.

file:flush ()

file에 쓴 데이터를 저장한다.

file:lines (···)

반복자 함수를 반환한다. 호출할 때마다 그 함수는 지정한 형식에 따라 파일을 읽어 들인다. 형식을 주지 않으면 기본으로 "l"을 쓴다. 예를 들어 다음처럼 쓰면

for c in file:lines(1) do body end

현재 위치부터 파일의 모든 문자들에 대해 반복하게 된다.io.lines와 달리 이 함수는 루프가 끝날 때 파일을 닫지 않는다.

file:read (···)

지정한 형식들에 따라 파일file을 읽는다. 각 형식에 대해 읽어 들인 문자들을 가지고 문자열이나 수를 반환하며, 지정한 형식으로 데이터를 읽을 수 없으면fail을 반환한다. (그 경우 이어지는 형식들은 읽지 않는다.) 인자 없이 호출할 때의 기본 형식은 다음 행 읽기다. (아래 참고.)

사용 가능한 형식은 다음과 같다.

  • "n":루아 어휘 규정에 따라 수를 읽어서 실수나 정수로 반환한다. (숫자 앞에 공백과 부호가 올 수 있다.) 이 형식에서는 입력 열이 유효한 수 시작부면 항상 최대한 읽어 들인다. 그 시작부가 유효한 수로 이어지지 않거나 (예: 빈 문자열, "0x", "3.4e-") 너무 길면 (200글자를 넘으면) 버리고서fail을 반환한다.
  • "a":현재 위치부터 파일을 통째로 읽어 들인다. 파일 끝에서는 빈 문자열을 반환한다. 이 형식은 절대 실패하지 않는다.
  • "l":다음 행을 읽어 들이며 개행을 생략한다. 파일 끝에서는fail을 반환한다. 기본 형식이다.
  • "L":다음 행을 읽어 들이며 개행 문자가 있으면 유지한다. 파일 끝에서는fail을 반환한다.
  • 수:이 바이트 개수만큼 문자열을 읽어 들인다. 파일 끝에서는fail을 반환한다.수가 0이면 아무것도 읽지 않고 빈 문자열을 반환하되, 파일 끝이면fail을 반환한다.

형식 "l"과 "L"은 텍스트 파일에만 써야 할 것이다.

file:seek ([whence [, offset]])

파일 위치를 다음과 같이 문자열whence로 나타낸 기준점에offset을 더한 위치로 설정하고, 파일 시작점을 기준으로 한 파일 위치를 얻는다.

  • "set":위치 0(파일 시작점) 기준
  • "cur":현재 위치 기준
  • "end":파일 끝 기준

성공 시seek은 파일 시작점부터 바이트 단위로 잰 최종 파일 위치를 반환한다. 실패하면fail과 오류 설명 문자열을 반환한다.

whence의 기본값은"cur"이고offset은 0이다. 그래서file:seek()호출은 현재 파일 위치를 변경 없이 반환한다.file:seek("set")호출은 위치를 파일 시작으로 설정한다. (그리고 0을 반환한다.)file:seek("end")호출은 위치를 파일 끝으로 설정하고 파일 크기를 반환한다.

file:setvbuf (mode [, size])

파일의 버퍼링 방식을 설정한다. 세 가지 방식이 있다.

  • "no":버퍼링 없음.
  • "full":최대 버퍼링.
  • "line":행 버퍼링.

뒤의 두 경우에서size는 바이트 단위 버퍼 크기 힌트다. 기본값은 적절한 크기다.

각 방식의 구체적인 동작 방식에는 이식성이 없다. 자세한 내용은 사용 플랫폼의 ISO C 함수setvbuf를 확인해 보라.

file:write (···)

인자 각각의 값을file에 쓴다. 인자는 문자열이나 수여야 한다.

성공 시 이 함수는file을 반환한다.

6.9 –운영 체제 기능

이 라이브러리는 테이블os를 통해 구현되어 있다.

os.clock ()

프로그램이 사용한 CPU 시간의 초 단위 근삿값을 반환한다. ISO C 함수clock이 반환하는 그 값이다.

os.date ([format [, time]])

문자열format의 형식에 따라서 날짜와 시간을 담은 문자열 내지 테이블을 반환한다.

time인자가 있으면 그 시간을 사용한다. (이 값에 대한 설명은os.time함수를 보라.) 없으면 현재 시간을 사용한다.

format이 '!'으로 시작하면 협정 세계시를 사용한다. 선택적인 이 문자 다음에format이 문자열 "*t"이면 테이블을 반환한다. 그 테이블에는year,month(1–12),day(1–31),hour(0–23),min(0–59),sec(0–61, 윤초 때문),wday(주별 날 번호, 1–7, 일요일이 1),yday(연별 날 번호, 1–366),isdst(일광 절약 플래그, 불리언) 필드가 있다. 마지막 필드는 해당 정보를 얻을 수 없으면 없을 수도 있다.

format이 "*t"가 아니면 ISO C 함수strftime과 같은 규칙에 따라 서식을 준 문자열로 일시를 반환한다.

format이 없는 경우 기본값은 "%c"이며, 현재 로캘을 이용해 사람이 읽을 수 있는 날짜 및 시간 표현을 내놓는다.

C 함수gmtime과 C 함수localtime을 쓰기 때문에 POSIX를 준수하지 않는 시스템에서는 이 함수가 스레드에 안전하지 않을 수 있다.

os.difftime (t2, t1)

시간t1부터 시간t2까지의 차이를 초 단위로 반환한다. (시간 값들은os.time이 반환한 것이다.) POSIX, 윈도우, 기타 일부 시스템에서 이 값은t2-t1그대로다.

os.execute ([command])

이 함수는 ISO C 함수system과 동등하다.command를 운영 체제 셸로 전달해서 실행하게 한다. 명령이 성공적으로 종료되었으면 첫 번째 결과가true고, 아니면fail이다. 그 첫 번째 결과에 더해서 다음과 같이 문자열과 수를 반환한다.

  • "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의 값을 반환한다. 그 변수가 정의되어 있지 않으면fail을 반환한다.

os.remove (filename)

지정한 이름의 파일을 (POSIX 시스템에서는 빈 디렉터리도 가능) 삭제한다. 실패하면fail에 더해서 오류 설명 문자열과 오류 코드를 반환한다. 아니면 참을 반환한다.

os.rename (oldname, newname)

이름이oldname인 파일이나 디렉터리의 이름을newname으로 바꾼다. 실패하면fail에 더해서 오류 설명 문자열과 오류 코드를 반환한다. 아니면 참을 반환한다.

os.setlocale (locale [, category])

프로그램의 현재 로캘을 설정한다.locale은 로캘을 지정하는 시스템별 문자열이다.category는 바꿀 범주를 나타내는 선택적 문자열이다."all","collate","ctype","monetary","numeric","time"중 하나이며, 기본 범주는"all"이다. 새 로캘의 이름을 반환하며, 요청에 응할 수 없으면fail을 반환한다.

locale이 빈 문자열이면 현재 로캘을 구현체에서 정의한 시스템 기본 로캘로 설정한다.locale이 문자열 "C"이면 현재 로캘을 표준 C 로캘로 설정한다.

첫 번째 인자를nil로 해서 호출하면 지정한 범주에 대해 현재 로캘의 이름을 반환하기만 한다.

C 함수setlocale을 이용하기 때문에 스레드에 안전하지 않을 수 있다.

os.time ([table])

인자 없이 호출하면 현재 시간을 반환한다. 아니면 지정한 테이블에 명시된 지역 날짜 및 시간을 나타내는 시간을 반환한다. 그 테이블에는year,month,day필드가 꼭 있어야 하며,hour(기본값 12),min(기본값 0),sec(기본값 0),isdst(기본값nil) 필드가 있을 수 있다. 다른 필드들은 무시한다. 이 필드들에 대한 설명은os.date함수를 보라.

함수 호출 시 이 필드들의 값이 반드시 유효 범위 내에 있어야 하는 것은 아니다. 예를 들어sec이 -10이면 다른 필드들이 가리키는 시간에서 10초 전을 뜻한다.hour가 1000이면 다른 필드들이 가리키는 시간에서 1000시간 후를 뜻한다.

반환하는 값이 수인데 그 의미가 시스템에 따라 다르다. POSIX, 윈도우, 기타 일부 시스템에서 이 수는 어떤 기준 시간("에포크") 이후로 지난 초의 수를 센 것이다. 다른 시스템에서는 그 의미가 명세되어 있지 않으므로time이 반환한 수를os.dateos.difftime의 인자로만 쓸 수 있다.

테이블을 줘서 호출하면os.date함수 설명에 나온 모든 필드들을 정규화해 주기도 한다. 그래서 그 값들이 호출 전과 같은 시간을 나타내되 유효 범위 안에 있게 된다.

os.tmpname ()

임시 파일에 쓸 수 있는 파일 이름을 문자열로 반환한다. 사용 전에 파일을 명시적으로 열어야 하며 더는 필요 없을 때 명시적으로 삭제해야 한다.

POSIX 시스템에서 이 함수는 보안상 위험을 피하기 위해 (이름을 얻는 시점과 파일을 생성하는 시점 사이에 다른 누군가가 잘못된 권한으로 그 파일을 생성할 수도 있다.) 그 이름으로 파일을 만들기까지 한다. 사용하려면 마찬가지로 파일을 열어야 하며 (사용하지 않은 경우에도) 파일을 삭제해야 한다.

가능하다면 프로그램이 끝날 때 파일을 자동으로 삭제해 주는io.tmpfile을 쓰는 게 바람직할 수 있다.

6.10 –디버그 라이브러리

이 라이브러리는 디버그 인터페이스(4.7절)의 기능들을 루아 프로그램에 제공한다. 이 라이브러리를 사용할 때는 주의를 기울여야 한다. 여러 함수가 루아 코드에 대한 기본적인 가정(예를 들면 외부에서 함수의 지역 변수에 접근할 수 없고, 루아 코드에서 userdata 메타데이터를 바꿀 수 없고, 루아 프로그램이 죽지 않음)을 깨며, 그래서 안전했을 코드를 위험한 상태로 만들 수 있다. 또한 이 라이브러리의 일부 함수들은 느릴 수 있다.

이 라이브러리의 모든 함수들을debug테이블에 담아서 제공한다. 스레드를 대상으로 동작하는 함수들에는 대상 스레드를 나타내는 선택적인 첫 번째 인자가 있다. 기본값은 항상 현재 스레드다.

debug.debug ()

대화형 모드로 들어가서 사용자가 입력하는 각 문자열을 실행한다. 간단한 명령들과 다른 디버그 기능들을 이용해 전역 및 지역 변수를 조사하고, 그 값을 바꾸고, 식을 평가하는 등의 일을 할 수 있다. 단어cont만 있는 행을 입력하면 이 함수가 끝나고 호출자가 실행을 이어 나간다.

참고로debug.debug에서의 명령은 문법적으로 어떤 함수에도 포함되지 않으며, 따라서 지역 변수에 직접 접근하지 못한다.

debug.gethook ([thread])

스레드의 현재 훅 설정을debug.sethook함수로 설정한 대로 세 값(현재 훅 함수, 현재 훅 마스크, 현재 훅 카운트)으로 반환한다.

활성 훅이 없으면fail을 반환한다.

debug.getinfo ([thread,] f [, what])

함수에 대한 정보를 담은 테이블을 반환한다.f의 값으로 직접 함수를 줄 수도 있고 수를 줄 수도 있다. 수는 지정한 스레드의 호출 스택f번 단계에서 실행 중인 함수를 뜻한다. 0번 단계는 현재 함수(getinfo자체)이고 1번 단계는getinfo를 호출한 함수인 식이다. (꼬리 호출은 스택에서 자리를 차지하지 않으므로 제외된다.)f가 활성 함수 개수보다 큰 수이면getinfo가fail을 반환한다.

lua_getinfo가 반환하는 모든 필드가 반환되는 테이블에 담길 수 있으며, 문자열what으로 어느 필드들을 채울지 지정한다.what의 기본값은 유효 행 테이블을 제외하고 가능한 모든 정보를 얻는 것이다. 옵션 'f'가 있으면func라는 필드에 함수 자체를 추가한다. 옵션 'L'이 있으면activelines라는 필드에 유효 행 테이블을 추가한다.

예를 들어 식debug.getinfo(1,"n").name은 적당한 이름이 있으면 현재 함수의 이름을 반환하며, 식debug.getinfo(print)는print함수에 대해 얻을 수 있는 모든 정보를 담은 테이블을 반환한다.

debug.getlocal ([thread,] f, local)

스택의f단계에 있는 함수에서 인덱스가local인 지역 변수의 이름과 값을 반환한다. 이 함수는 명시적인 지역 변수뿐만 아니라 매개변수와 임시 값에도 접근할 수 있다.

첫 번째 매개변수 내지 지역 변수의 인덱스가 1이고 코드에 선언된 순서대로 이어지는 식이며, 함수의 현재 유효 범위에서 활성인 변수들만 센다. 컴파일 시점 상수는 컴파일러가 최적화해 버렸다면 이 목록에 등장하지 않을 수도 있다. 음수 인덱스는 가변 인자를 가리킨다. -1이 첫 번째 가변 인자다. 지정한 인덱스의 변수가 없으면fail을 반환하며, 범위 밖의 단계로 호출하면 오류를 던진다. (debug.getinfo를 호출해서 단계가 유효한지 확인할 수 있다.)

'(' (여는 괄호)로 시작하는 변수 이름은 이름을 모르는 변수(루프 제어 변수 같은 내부 변수나 디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.

매개변수f가 함수일 수도 있다. 그 경우getlocal은 그 함수 매개변수들의 이름만 반환한다.

debug.getmetatable (value)

지정한value의 메타테이블을 반환한다. 메타테이블을 가지고 있지 않으면nil을 반환한다.

debug.getregistry ()

레지스트리 테이블을 반환한다. (4.3절참고.)

debug.getupvalue (f, up)

함수f에서 인덱스가up인 upvalue의 이름과 값을 반환한다. 지정한 인덱스의 upvalue가 없으면fail을 반환한다.

(루아 함수의 경우 upvalue는 함수에서 사용하여 그 결과로 클로저에 포함된 외부의 지역 변수다.)

C 함수의 경우 이 함수는 모든 upvalue에 이름으로 빈 문자열""을 쓴다.

변수 이름 '?' (물음표)는 이름을 모르는 변수(디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.

debug.getuservalue (u, n)

userdatau에 연계된n번째 사용자 값과 불리언을 반환하는데, 그 userdata에 그 값이 없는 경우 불리언 값이false다.

debug.setcstacklimit (limit)

C 스택의 새 제한치를 설정한다. 이 제한치는 루아에서 중첩 호출이 얼마나 깊어질 수 있는지 통제하는 것인데, 스택 넘침을 피하기 위한 것이다. 제한치가 너무 작으면 무의미하게 재귀 호출을 제약한다. 제한치가 너무 크면 인터프리터가 스택 넘침으로 죽을 가능성이 생긴다. 아쉽게도 어떤 플랫폼에서 안전한 가장 큰 제한치를 미리 알 수 있는 방법은 없다.

루아 코드에서 이뤄진 각 호출을 한 단위로 계산한다. 다른 동작들(예: C에서 루아로 이뤄진 호출이나 코루틴 재개하기)은 더 높은 비용으로 계산할 수 있다.

이 함수에는 다음 제약이 있다.

  • 메인 코루틴(스레드)에서만 호출할 수 있다.
  • 스택 오버플로우 오류를 처리하는 동안에는 호출할 수 없다.
  • limit가 40000보다 작아야 한다.
  • limit가 사용 중인 C 스택 양보다 작을 수 없다.

이 제약을 따르지 않고 호출하면 거짓 값을 반환한다. 올바로 호출하면 이전 제한치를 반환한다.

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를 할당한다. 지정한 인덱스의 지역 변수가 없으면fail을 반환하며, 범위 밖의level로 호출하면 오류를 던진다. (getinfo를 호출해서 단계가 유효한지 확인할 수 있다.) 그 외 경우에는 그 지역 변수의 이름을 반환한다.

변수 인덱스와 이름에 대한 자세한 내용은debug.getlocal을 보라.

debug.setmetatable (value, table)

(nil일 수 있는) 지정한table을 지정한value의 메타테이블로 설정한다.value를 반환한다.

debug.setupvalue (f, up, value)

함수f에서 인덱스가up인 upvalue에 값value를 할당한다. 지정한 인덱스의 upvalue가 없으면fail을 반환한다. 그 외 경우에는 그 upvalue의 이름을 반환한다.

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

debug.setuservalue (udata, value, n)

지정한value를 지정한udata에 연계된n번째 사용자 값으로 설정한다.udata가 full userdata여야 한다.

udata를 반환한다. userdata에 그 값이 없으면fail을 반환한다.

debug.traceback ([thread,] [message [, level]])

message가 있는데 문자열이 아니고nil도 아니면 다른 처리 없이message를 반환한다. 그렇지 않으면 호출 스택의 트레이스백을 담은 문자열을 반환한다. 선택적인 문자열message를 트레이스백 앞쪽에 덧붙인다. 선택적인 수level은 어느 단계에서 트레이스백을 시작할지를 나타낸다. (기본값은 1, 즉traceback을 호출한 함수다.)

debug.upvalueid (f, n)

지정한 함수의n번째 upvalue에 대한 고유 식별자를 (light userdata 형태로) 반환한다.

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

debug.upvaluejoin (f1, n1, f2, n2)

루아 클로저f1의n1번째 upvalue가 루아 클로저f2의n2번째 upvalue를 가리키게 만든다.

7 –단독형 루아

루아는 호스트 C 프로그램에 내장되는 확장 언어로 설계되었지만 단독 언어로도 자주 쓰인다. 단독 언어 루아를 위한lua라는 인터프리터가 표준 배포 파일에 딸려 있다. 단독 인터프리터에는 모든 표준 라이브러리가 포함되어 있다. 사용법은 이렇다.

lua [options] [script [args]]

옵션은 이렇다.

  • -estat:문자열stat실행
  • -i:script실행 후 대화형 모드 진입
  • -lmod:mod를 "require" 하고 결과를 전역mod에 할당
  • -v:버전 정보 출력
  • -E:환경 변수 무시
  • -W:경고 켜기
  • --:옵션 처리 중단
  • -:stdin을 파일처럼 실행하고 옵션 처리 중단

lua는 옵션들을 처리한 후 주어진script를 실행한다.lua를 인자 없이 호출하면 표준 입력(stdin)이 터미널일 때는lua -v -i처럼 동작하고 아닐 때는lua -처럼 동작한다.

-E옵션 없이 호출 시 인터프리터는 인자 실행에 앞서 환경 변수LUA_INIT_5_4를 (버전 붙은 이름이 정의되어 있지 않으면LUA_INIT을) 확인한다. 변수 내용이@파일명형식이면lua가 그 파일을 실행한다. 그렇지 않으면lua가 그 문자열 자체를 실행한다.

-E옵션을 줘서 호출 시 루아는 어떤 환경 변수도 확인하지 않는다. 특히package.pathpackage.cpath의 값을luaconf.h에 정의된 기본 경로로 설정한다.

옵션-e,-l,-W는 등장한 순서대로 처리한다. 예를 들어 다음과 같이 호출 시,

$ lua -e 'a=1' -llib1 script.lua

먼저a를 1로 설정하고, 다음으로 라이브러리lib1을 require 하고, 마지막으로 인자 없이script.lua파일을 실행한다. (여기서$는 셸 프롬프트다. 사용자마다 다를 수 있다.)

코드 실행 전에lua는 모든 명령행 인자를arg라는 전역 테이블에 모은다. 스크립트 이름이 인덱스 0으로 가고 스크립트 이름 다음의 첫 번째 인자가 인덱스 1로 가고 하는 식이다. 그리고 스크립트 이름 앞의 인자들이 (즉 인터프리터 이름과 그 옵션들이) 음수 인덱스로 간다. 예를 들어 다음 호출에서,

$ lua -la b.lua t1 t2

테이블이 다음과 같다.

arg = { [-2] = "lua", [-1] = "-la", [0] = "b.lua", [1] = "t1", [2] = "t2" }

호출에 script가 없으면 인터프리터가 인덱스 0으로 가고 다른 인자들이 뒤따른다. 예를 들어 다음 호출이

$ lua -e "print(arg[1])"

"-e"를 찍는다. script가 있으면 인자arg[1], ···,arg[#arg]로 그 스크립트가 호출된다. 루아의 여느 청크들처럼 스크립트를 가변 인자 함수로 컴파일한다.

대화형 모드에서 루아는 반복해서 프롬프트를 표시하고 행 입력을 기다린다. 행을 읽은 후 루아는 먼저 식으로 해석하려고 시도한다. 성공하면 그 값을 찍는다. 아니면 그 행을 문으로 해석한다. 적어 준 문이 불완전하면 인터프리터가 다른 프롬프트를 표시하며 문이 완성되기를 기다린다.

전역 변수_PROMPT가 문자열을 담고 있으면 그 값을 프롬프트로 쓴다. 마찬가지로 전역 변수_PROMPT2가 문자열을 담고 있으면 그 값을 (문이 미완성인 동안 보이는) 보조 프롬프트로 쓴다.

스크립트에서 보호 안 된 오류가 발생하면 인터프리터가 그 오류를 표준 오류 스트림으로 보고한다. 오류 객체가 문자열이 아니지만 메타메소드__tostring을 가지고 있으면 인터프리터가 그 메타메소드를 호출해서 최종 메시지를 만든다. 그렇지 않으면 인터프리터가 오류 객체를 문자열로 변환하고 스택 트레이스백을 덧붙인다. 경고가 켜져 있을 때는 경고를 표준 오류 출력으로 그냥 찍는다.

정상적으로 끝날 때 인터프리터에서 메인 루아 상태를 닫는다. (lua_close참고.) 이 단계를 피하고 싶으면 스크립트에서os.exit호출로 종료하면 된다.

유닉스 시스템에서 루아를 스크립트 인터프리터로 쓸 수 있게 하기 위해 루아는 파일 첫 행이#로 시작하면 그 행을 건너뛴다. 그래서chmod +x하고 다음처럼#!형식을 쓰면 루아 스크립트를 실행 프로그램으로 만들 수 있다.

#!/usr/local/bin/lua

당연히 루아 인터프리터 위치는 머신마다 다를 수 있다.PATH안에lua가 있다면 다음이 더 이식성 좋은 방식이다.

#!/usr/bin/env lua

8 –이전 버전과 호환되지 않는 점

프로그램을 루아 5.3에서 루아 5.4로 옮기면서 발견할 수 있는 비호환 사항들을 나열한다.

어떤 사항들은 적절한 옵션을 써서 루아를 컴파일하는 것으로 (파일luaconf.h참고) 피할 수 있다. 하지만 그 호환성 옵션들은 향후에 모두 없어질 것이다. 이런 호환성 옵션들이 없어질 때 대개 호환성 이슈들이 발생한다. 따라서 기회 있을 때마다 모든 호환성 옵션을 끄고 컴파일한 루아 버전으로 코드를 확인해 보는 게 좋다. 그러면 루아 새 버전으로 옮기는 게 쉬워진다.

루아 버전이 바뀔 때 상수의 숫자 값이나 매크로 함수의 구현처럼 프로그램 소스 코드 변경이 필요치 않은 방식으로는 언제든 C API가 바뀔 수 있다. 따라서 절대로 루아 버전들 간에 바이너리가 호환된다고 가정해선 안 된다. 항상 루아 API 사용 프로그램을 새 버전으로 다시 컴파일해야 한다.

또한 루아 버전이 바뀌면서 언제든 사전 컴파일 청크의 내부 표현 방식이 바뀔 수 있다. 즉, 루아 버전들 간에 사전 컴파일 청크가 호환되지 않는다.

공식 배포본 내의 표준 경로가 버전들 간에 바뀔 수 있다.

8.1 –언어에서 바뀐 점

  • 산술 연산과 비트 연산에서 문자열을 수로 강제 변환하는 동작이 코어 언어에서 제거되었다. 문자열 라이브러리에서 산술 연산에 (비트 연산은 아님) 문자열 메타메소드를 써서 비슷한 일을 해 준다. 하지만 이전 버전들과 달리 새 구현에서는 문자열에 있는 수의 암묵적 타입을 유지한다. 예를 들어"1" + "2"의 결과가 이제 실수가 아니라 정수다.
  • 리터럴 10진 정수 상수 값이 넘치는 경우에 되감는 게 아니라 실수로 읽어 들인다. 이전 동작 방식(정수로 읽어 들이고 되감기)을 원한다면 16진 표기를 쓰면 된다.
  • __lt메타메소드를 써서__le를 흉내내는 동작이 제거되었다. 그 메타메소드가 필요할 때는 명시적으로 정의해야 한다.
  • 정수에 대한 수열형for루프의 세부 동작이 일부 바뀌었다. 특히 제어 변수가 절대 되감기지 않는다.
  • goto의 레이블을 같은 이름의 레이블이 보이는 곳에서 선언할 수 없다. 그 다른 레이블이 감싸는 블록에 정의된 것이라도 마찬가지다.
  • 객체를 마무리할 때 함수가 아닌__gc메타메소드를 무시하지 않는다. 어떤 값이든 존재하면 호출된다. (호출 가능하지 않은 값이면 종료자 호출 시의 다른 오류와 마찬가지로 경고가 발생하게 된다.)

8.2 –라이브러리에서 바뀐 점

  • print함수가 인자에 서식을 주기 위해tostring을 호출하지 않는다. 그 기능성이 내장되었다. 값이 찍히는 방식을 바꾸려면__tostring을 써야 한다.
  • math.random함수에서 쓰는 유사 난수 생성기가 이제는 어느 정도 난수인 시드로 시작한다. 그리고 다른 알고리즘을 쓴다.
  • 기본적으로utf8라이브러리의 디코딩 함수들은 서러게이트를 유효한 코드 포인트로 받아들이지 않는다. 그 함수들에 추가된 매개변수를 쓰면 동작이 더 관대해진다.
  • collectgarbage함수의 옵션 "setpause"와 "setstepmul"이 폐기 예정이 되었다. 새 옵션 "incremental"을 사용해 설정해야 한다.
  • io.lines함수가 이제 값 한 개가 아니라 네 개를 반환한다.load(io.lines(filename, "L"))처럼 선택적 매개변수가 있는 다른 함수의 유일한 인자로 쓸 때 문제가 될 수 있다. 고치려면 호출을 괄호로 감싸서 결과를 한 개로 조정하면 된다.

8.3 –API에서 바뀐 점

  • full userdata가 이제 임의 개수의 연계 사용자 값을 가진다. 그래서 함수lua_newuserdata,lua_setuservalue,lua_getuservalue가 추가 인자가 있는lua_newuserdatauv,lua_setiuservalue,lua_getiuservalue로 교체되었다.

    호환성을 위해 이전 이름들도 단일 사용자 값을 가정한 매크로 형태로 계속 동작한다. 하지만 사용자 값이 0개인 userdata가 메모리 측면에서 더 효율적이라는 점을 생각하라.

  • lua_resume함수에 매개변수가 추가되었다. 이 출력 매개변수는 코루틴이 양보 내지 반환한 스택 상의 값들 개수를 반환한다. (이전 버전에서는 그 값들이 스택 전체였다.)

  • lua_version함수가 버전 번호의 주소가 아니라 버전 번호를 반환한다. 루아 코어가 같은 코어의 자체 static 사본을 쓰는 라이브러리와도 잘 동작해야 한다. 따라서 같은 주소 공간을 쓰고 있는지 여부를 확인할 필요가 없다.

  • 상수LUA_ERRGCMM이 제거되었다. 종료자 내의 오류는 절대 전파되지 않으며 경고만 발생한다.

  • lua_gc함수의 옵션LUA_GCSETPAUSE와LUA_GCSETSTEPMUL이 폐기 예정이 되었다. 새 옵션LUA_GCINC를 사용해 설정해야 한다.

9 –루아 전체 문법

다음은 확장 BNF로 된 루아의 전체 문법이다. 확장 BNF에서 늘 그렇듯 {A}는 0개 이상의 A를 뜻하고 [A]는 선택적인 A를 뜻한다. (연산자 우선순위는3.4.8절참고. 말단 Name, Numeral, LiteralString에 대한 설명은3.1절참고.)

chunk ::= block block ::= {stat} [retstat] stat ::= ‘;’ | varlist ‘=’ explist | functioncall | label | break | goto Name | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | for namelist in explist do block end | function funcname funcbody | local function Name funcbody | local attnamelist [‘=’ explist] attnamelist ::= Name attrib {‘,’ Name attrib} attrib ::= [‘<’ Name ‘>’] retstat ::= return [explist] [‘;’] label ::= ‘::’ Name ‘::’ funcname ::= Name {‘.’ Name} [‘:’ Name] varlist ::= var {‘,’ var} var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name namelist ::= Name {‘,’ Name} explist ::= exp {‘,’ exp} exp ::= nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | prefixexp | tableconstructor | exp binop exp | unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’ functioncall ::= prefixexp args | prefixexp ‘:’ Name args args ::= ‘(’ [explist] ‘)’ | tableconstructor | LiteralString functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end parlist ::= namelist [‘,’ ‘...’] | ‘...’ tableconstructor ::= ‘{’ [fieldlist] ‘}’ fieldlist ::= field {fieldsep field} [fieldsep] field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp fieldsep ::= ‘,’ | ‘;’ binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | and | or unop ::= ‘-’ | not | ‘#’ | ‘~