나루 프로그래밍 언어

나루는 세계 정복을 위해 설계된 프로그래밍 언어입니다. 현재 알려진 바로는 아직 세계 정복은 이루어지지 않았으며, 따라서 그 이전까지는 이 웹사이트는 공사중입니다.

이 웹사이트는 narunaru.org, narucode.orgnoe.mearie.org의 일부에서 볼 수 있습니다. The English version of this document is available here.

1 진지하게 말하자면…

나루(naru)는 강 성훈이 2005년 이래로 설계하고 있으며 아직도 설계 중인 프로그래밍 언어입니다. 나루에는 몇 가지 목표가 있는데:

적절한 표현력과 간결함

표현력과 간결함은 대부분 서로 상보되는 개념으로, 기능을 많이 넣을 수록 코드의 간결함은 보통 떨어집니다. 나루는 둘 사이에 적절한 타협점을 제공합니다. (그리고 미리 말하지만 그 “타협점”이라는 게 리스프는 아닙니다… 솔직히 s-expression은 좀 그래요.)

올바른 방법을 기본으로

많은 사용자들은 언어 설계자가 (의도적이든 의도적이지 않든) 선택한 기본값을 아무 생각 없이 따라가기 때문에, 언어 설계자의 초기 선택은 매우 중요합니다. 예를 들자면 유니코드를 지원하지 않는 언어에서 하나의 char가 항상 진짜 문자 하나에 대응된다고 생각하면 나중에 코드를 뜯어 고쳐야 할 일이 생기겠지요. (사실 유니코드 문자열을 지원하는 언어라고 이 문제가 없지는 않습니다.) 나루는 일을 하는 올바른 방법을 훨씬 쉽도록 하여, 사용자가 의도치 않더라도 가장 쉬운 방법을 택하면 자동으로 올바른 선택을 하도록 합니다.

정적 언어와 동적 언어의 결합

흔히 정적 언어와 동적 언어는 기름과 물처럼 섞일 수 없는 관계로 인식되어, 둘 사이에 위치하는 언어를 찾기는 상당히 힘듭니다. 여기에는 이 중간에 위치한 언어가 정적 언어와 동적 언어의 장점을 모두 제공하지 않는다는 점도 한 몫 하는데, 정적 언어라면 성능, 신뢰성 및 (음, 타입 시스템이 충분히 좋다면) 안전성이 있겠고, 동적 언어라면 강력한 표현력과 빠르고 쉬운 개발이 있겠습니다. 나루는 두 장점을 모두 제공하려고 노력합니다.

설계자의 개인 취향

뭐, 예를 들자면 나루의 문법은 어떤 면에서는 파이썬이나 루비와 꽤 유사한데, 이는 제가 이들 언어에 익숙하기 때문입니다. 하지만 다른 많은 면은 필요에 따라 다른 언어에서 유래한 것도 많으며(예를 들어 속성·메소드 접근에 공백을 쓰는 것은 ooc에서 영향을 받았습니다), 아예 완전히 새로이 만든 기능(with라거나)도 있습니다. 또한 저는 보통 깔끔하고 직관적인 설계를 추구하기 때문에—너무 당연해서 실수를 하고 싶어도 할 수 없는—, 언어 설계에도 이 철학이 많이 녹아 있습니다.

개발을 시작한 이래 나루는 이들 목표를 만족시키기 위해 몇 번의 대대적인 수정을 거쳤으며, 현재 설계는 “제 4판”이라고 불리고 있습니다. 아직 아무 구현체도 존재하지는 않습니다만, 개략적인 설계가 완료되는 대로 참조 구현체가 만들어질 것입니다.

2 어떻게 생겼나요?

이 코드 예제는 PHP의 getimagesize 함수를 간단하게 구현한 것입니다:

use naru

ImageType := type (:png | :gif | :jpeg)

(-- 주어진 이미지 스트림에서 이미지 포맷, 폭, 높이의 순서쌍을 반환하거나,
    오류가 발생하면 none을 반환한다. PNG, GIF (87a 및 89a) 및 JPEG
    (JFIF만 지원) 파일 포맷을 지원함. --)
imagesize(f: Reader) -> (ImageType,Int,Int)? := fun
    imgtype: Option{ImageType} = none

    f position = 0
    header = f read(24)
    if header length != 24 then return none end    -- 파일이 너무 짧음

    if header[..!8] == b"\x89PNG\x0d\x0a\x1a\x0a" then
        width, height = header[16..!24] asInt32(:big)
        imgtype = :png
    elseif header[..!6] in {b"GIF87a", b"GIF89a"} then
        width, height = header[6..!10] asUInt16(:little)
        imgtype = :gif
    elseif header[..!4] == b"\xff\xd8\xff\xe0" and header[6..!10] == b"JFIF" then
        blockgen() := fun
            f position = 2
            while f eof
                f skipwhile(0xff)
                blocktype, blocksize = f read(3) unpack([UInt8, UInt16], :big)
                savedpos = f position
                yield blocktype, blocksize
                f position = savedpos + blocksize - 2   -- 2 for blocksize
            end
        end

        -- SOFn (start-of-frame) 블록만 뽑아냄
        sofns = blockgen() map(fun (t, _) -> 0xc0 <= t <= 0xcf)
        for _ <- sofns
            -- precision 바이트는 사용하지 않음
            _, height, width = f read(5) unpack([Int8, UInt16, UInt16], :big)
            imgtype = :jpeg
            break
        end
    end

    if t <- imgtype then
        return (t, width, height)
    else
        return none
    end
end

(-- imagesize(Reader)와 같으나 파일 이름으로부터 스트림을 만든다. --)
imagesize(filename: String) := \
    fun -> imagesize(File(filename) open())

(-- 주어진 이미지 파일로부터 적절한 XHTML 텍스트를 반환한다. 만약 자동으로 이미지
    크기를 찾아 낼 수 없을 경우 width/height 속성이 없는 잘못된 XHTML 텍스트를
    반환할 수 있다. --)
htmlize(filename: String, alt: String = "") := fun
    escape(s) := fun s -> s replace("&", "&amp;") replace("<", "&lt;") replace(">", "&gt;")
    do
        _, width, height = imagesize(filename)
        return #"""<img src="#(escape(filename))" width="#width" height="#height"
                        alt="#(escape(alt))" />"""
    but
        -- 크기 정보를 얻는 데 실패했음
        return #"""<img src="#(escape(filename))" alt="#(escape(alt))" />"""
    end
end

당연하지만 이 코드에 나타난 어떤 기능도 확정된 건 아닙니다.

3 이거 그럴듯해 보이는데요, 이제 어쩌나요?

다음 링크를 따라가 보세요.

3.1 문서 목록

다음은 나루 제 4판에 대한 문서와 보고서입니다:

나루의 옛 버전에 대한 문서와 보고서도 역사적 목적으로 남아 있습니다:

3.2 난상 토론

오징어 IRC 네트워크#naru 채널에서 나루에 대한 토론을 할 수 있습니다.