말하는 방법은하나.

토파즈는 조판에 특화된 프로그래밍 언어입니다. 책부터 보고서와 청구서까지 인쇄용 문서를 만드는 프로그램에 쓰고, 명령줄 도구와 애플리케이션 로직도 작성할 수 있습니다. 같은 소스를 컴퓨터에서 실행하거나 브라우저용 패키지로 빌드하세요.

지금 실행하면 아래와 같은 결과를 얻습니다.

TOPAZ
function 인사하기(이름: string) -> string {
    return "안녕하세요, {이름}님!"
}

print(인사하기("토파즈"))
출력
안녕하세요, 토파즈님!

아틀라스

토파즈로 짓는 조판 도구

아틀라스는 원고를 인쇄용 책 지면으로 조판합니다. 아틀라스로 조판한 책의 한 쪽과 공개된 토파즈 소스의 일부를 함께 실었습니다. 소스의 함수 이름에는 한국어 조판 용어를 그대로 씁니다.

아틀라스로 조판한 한국어 책의 본문 18쪽
아틀라스로 조판한 책의 본문 18쪽
TOPAZ
function 다음은라틴공백아님(다음: Option<string>) -> bool {
  match 다음 {
    case Some(텍스트) => !라틴공백인가(텍스트)
    case None => true
  }
}
function 다음은줄머리금지없음(다음: Option<string>) -> bool {
  match 다음 {
    case Some(텍스트) => !일부줄머리금지(텍스트)
    case None => true
  }
}

아틀라스 홈페이지에 공개된 금칙분류.tpz의 일부

토파즈가 조판에 강한 이유

조판 용어가 곧 이름

금칙분류, 나쁨도처럼 조판에서 쓰는 말을 그대로 함수와 변수 이름으로 씁니다. 원고의 글자도 입력한 그대로 다룹니다.

문자열과 템플릿 →

미리보기와 출력이 같은 규칙

조판 규칙을 한 번 쓰면 같은 소스를 컴퓨터용 실행 파일과 브라우저용 패키지로 빌드합니다. 두 대상이 같은 언어 규칙을 따르므로 화면에서 확인한 규칙이 출력에도 그대로 쓰입니다.

인터프리터와 백엔드 →

계산이 조용히 틀리지 않음

정수는 64비트이고, 값이 넘치면 틀린 값으로 계속하지 않고 그 자리에서 멈춥니다. 줄 길이와 배치 비용을 정수로 셈하면 넘침이 조용한 오차로 남지 않습니다.

런타임 동작 →

빠뜨린 규칙은 빌드에서

금칙 분류처럼 경우가 정해진 목록을 열거형으로 두면 match가 모든 경우를 다루는지 컴파일러가 확인합니다. 새 경우를 더하면 그 경우를 아직 다루지 않은 match를 빌드가 알려 줍니다.

패턴과 제어 흐름 →

리스펙스

계산은 토파즈, 판단은 리스펙스

줄을 나누고 쪽을 짜는 계산은 토파즈가 합니다. 장을 어느 쪽에서 시작할지, 외톨이 줄을 몇 줄까지 둘지처럼 출판사와 책마다 달라지는 판단은 리스펙스 규칙으로 따로 씁니다. 토파즈 5.21에 든 리스펙스 1.21 평가기가 규칙을 정해진 한도 안에서 실행합니다. 규칙 파일을 바꾸고 잠금 파일을 다시 만들면 앱 코드를 고치지 않고 같은 원고를 다른 스타일로 짤 수 있습니다.

  • 규칙은 파일, 시스템 시계, 네트워크에 손대지 않습니다.
  • 한도를 넘으면 그 자리에서 멈춥니다.
  • 같은 규칙, 입력, 설정이면 매번 같은 판단을 냅니다.
LISPEX
(let ((최소-줄 2))
  (if (< input 최소-줄) "다음-쪽으로" "그대로"))

rules/외톨이-줄.lspx 전체

TOPAZ
import src.값 { 한자리정수, 문자열 }
import std.lispex { defaultLimits, evaluate }
import std.lispex.rules as rules

export function main(args: Array<string>, stdin: string) -> Result<int, string> {
    let 규칙 = rules.외톨이_줄()
    for 남은줄 in [1, 2] {
        match evaluate(규칙, 한자리정수(남은줄)?, defaultLimits(규칙)) {
            case Ok(Complete(결과)) => print("남은 줄 {남은줄}: {문자열(결과)}")
            case _ => return Err("규칙이 끝나지 않았습니다")
        }
    }
    Ok(0)
}
출력
남은 줄 1: 다음-쪽으로
남은 줄 2: 그대로

src/main.tpz 전체. 한자리정수와 문자열은 리스펙스 값을 바꾸는 작은 함수입니다.

리스펙스 규칙은 인터프리터와 네이티브 빌드에서 실행합니다. 매니페스트와 한도 파일까지 사용법은 리스펙스 규칙 실행하기 문서에 있습니다.

업무 규칙과 데이터 처리도

TOPAZ
function 할인율(고객: { 등급: string, 연수: int }) -> float {
    return match 고객 {
        case { 등급: "우수", 연수 } if 연수 > 5 => 0.3
        case { 등급: "우수" } => 0.2
        case { 연수 } if 연수 > 1 => 0.1
        case _ => 0.0
    }
}

print("{할인율({ 등급: "우수", 연수: 7 })}")
print("{할인율({ 등급: "신규", 연수: 0 })}")
출력
0.3
0.0
TOPAZ
function 정리(낱말들: Array<string>) -> Array<string> {
    return filter(낱말들, (낱말: string) => 낱말 != "")
}

function 외치기(낱말들: Array<string>) -> Array<string> {
    return map(낱말들, (낱말: string) => 낱말 + "!")
}

let 문장 = ["말하는", "", "방법은", "", "하나"]
    |> 정리
    |> 외치기
print("{문장}")
출력
[말하는!, 방법은!, 하나!]

동시성과 정리 작업 예제는 동시성과 Defer와 리소스 문서에 있습니다.