프로젝트

5.21로 옮기기

언어 모드를 바꾸고 5.21에서 없앤 형태를 값의 메서드나 std 모듈 호출로 바꾼 뒤 결과를 검사합니다. v5 이전 소스는 마지막 절에서 다룹니다.

토파즈 5.21은 print 같은 전역 함수, Math와 FS 같은 정적 네임스페이스, 표준 모듈 6개를 없앴습니다. 이 호출은 값의 메서드와 std 모듈로 옮겨 갑니다. 먼저 언어 모드를 바꾸고, 없앤 형태는 topaz check가 하나씩 짚어 주는 대로 고치세요.

토파즈를 설치하고 원본 소스, 입력, 출력의 사본을 보관하세요.

언어 모드 바꾸기

topaz.toml에서 language와 std를 "5.21"로 바꾸세요.

TOML
[package]
language = "5.21"

[dependencies]
std = "5.21"

토파즈 5.21은 topaz-5.21 언어 모드만 받습니다. 5.20 언어 모드로 남은 패키지는 unsupported language mode로 멈춥니다. topaz.toml 없이 파일 하나만 검사하면 이미 5.21로 검사합니다.

없앤 형태 찾기

다음 파일은 5.21에서 없앤 print를 아직 부릅니다.

print("ready")

old-forms.tpz로 저장하고 검사하세요.

BASH
topaz check old-forms.tpz

여기의 print처럼 없앤 호출에는 검사기가 TPZ5002를 알리고 5.21에서 쓸 호출을 알려 줍니다. import std.math처럼 없앤 표준 모듈을 가져오면 TPZ3001을 알리고 대신 쓸 메서드를 알려 줍니다.

출력
error[TPZ5002]: `print` is not bound; import std.io and use io.writeLine(value) in 5.21
 --> old-forms.tpz:1:1
  |
1 | print("ready")
  | ^^^^^

old-forms.tpz: 1 type diagnostic

메시지대로 고쳐 파일을 다시 저장하세요.

TOPAZ
import std.io

io.writeLine("ready")

이제 topaz check old-forms.tpz가 성공하고 topaz run old-forms.tpz는 ready를 출력합니다.

없앤 형태 바꾸기

첫째 열의 형태를 둘째 열의 형태로 바꾸세요. 셋째 열에 import가 있으면 파일 맨 위에 한 번 더하세요.

5.21에서 없앤 형태대신 쓸 형태먼저 가져올 모듈
print(x)io.writeLine(x)import std.io
input()io.readStdin()import std.io
open(p)io.open(p)import std.io
assert(c)test.assert(c)import std.test
map(xs, f), filter(xs, f), reduce(xs, z, f)xs.map(f), xs.filter(f), xs.reduce(z, f)
toFloat(n), toInt(s), toIntRadix(s, r), fromCodePoint(n)n.toFloat(), s.toInt(), s.toIntRadix(r), n.toCodePoint()
Math.sqrt(x), Math.abs(x), Math.sin(x), Math.cos(x), Math.tan(x), Math.isNaN(x), Math.isFinite(x)x.sqrt(), x.abs(), x.sin(), x.cos(), x.tan(), x.isNaN(), x.isFinite()
Math.floor(x), Math.ceil(x), Math.round(x)x.floor(), x.ceil(), x.round()
Math.parseFloat(s)s.parseFloat()
Math.min(a, b), Math.max(a, b)a.atMost(b), a.atLeast(b)
JSON.parse(s), JSON.stringify(v), JSON.parseAs<T>(s)json.parse(s), json.stringify(v), json.parseAs<T>(s)import std.json
JSON.decode<T>(v)v.decode<T>()
FS.readText(p), FS.writeText(p, text), FS.readBytes(p), FS.writeBytes(p, bytes), FS.list(p)fs.readText(p), fs.writeText(p, text), fs.readBytes(p), fs.writeBytes(p, bytes), fs.list(p)import std.fs
CSV.parse(s), CSV.parseWithHeader(s), CSV.stringify(rows), CSV.stringifyWithHeader(rows, columns)csv.parse(s), csv.parseWithHeader(s), csv.stringify(rows), csv.stringifyWithHeader(rows, columns)import std.csv
TOML.parse(s), TOML.stringify(v), TOML.fromJson(v)toml.parse(s), toml.stringify(v), toml.fromJson(v)import std.toml
TOML.toJson(t)t.toJson()
Test.assert(c), Test.assertEq(a, b), Test.assertNe(a, b), Test.assertContains(text, part)test.assert(c), test.assertEq(a, b), test.assertNe(a, b), test.assertContains(text, part)import std.test
Test.assertOk(result), Test.assertErr(result), Test.assertSome(option), Test.assertNone(option), Test.assertGolden(name, actual)test.assertOk(result), test.assertErr(result), test.assertSome(option), test.assertNone(option), test.assertGolden(name, actual)import std.test
Encoding.utf8Encode(s), Encoding.utf8Decode(b)s.encodeUtf8(), b.decodeUtf8()
Encoding.hexEncode(b), Encoding.hexDecode(s)b.toHex(), Bytes.fromHex(s)
Encoding.base64Encode(b), Encoding.base64Decode(s)b.toBase64(), Bytes.fromBase64(s)
Hash.sha256(b), Hash.sha512(b), Hash.crc32(b)b.sha256(), b.sha512(), b.crc32()
Hash.hmacSha256(key, data)key.hmacSha256(data)
Codec.gzipCompress(b), Codec.gzipDecompress(b), Codec.deflateCompress(b), Codec.deflateDecompress(b)b.gzipCompress(), b.gzipDecompress(), b.deflateCompress(), b.deflateDecompress()
Codec.deflateFixedCompress(b), Codec.zlibFixedCompress(b), Codec.reedSolomon255223Protect(b)b.deflateFixedCompress(), b.zlibFixedCompress(), b.reedSolomon255223Protect()
Codec.zstdCompress(b, level), Codec.zstdDecompress(b)b.zstdCompress(level), b.zstdDecompress()
Cli.hasFlag(args, name), Cli.option(args, name), Cli.options(args, name), Cli.positionals(args)args.hasFlag(name), args.option(name), args.options(name), args.positionals()
Array.of(a, b)[a, b]
Set.of(a, b)set { a, b }
Map.new()map {}
Bytes.encodeUtf8(s), Bytes.concat(a, b)s.encodeUtf8(), a.concat(b)
BigInt.fromInt(n), Decimal.fromInt(n)n.toBigInt(), n.toDecimal()
import std.math, import std.encoding, import std.hash, import std.codec, import std.cliimport를 지우고 위 행의 메서드를 부르세요
import std.gen[for x in lo..hi => x], [false, true]
topaz lispex run리스펙스 소스는 lispex run, 내장 평가기는 topaz lispex embed run
topaz lispex infotopaz lispex embed info

x.floor(), x.ceil(), x.round(), x.trunc()는 int를 돌려줍니다. Math.floor(x)처럼 실수 결과가 필요하면 x.floor().toFloat()로 쓰고, ceil과 round에도 같은 방법을 씁니다. 새 정수 변환은 결과 범위를 검사합니다.

std.bytes, std.path, std.regex, std.url, std.date, std.bigint, std.decimal은 타입만 내보냅니다. 함수는 해당 값의 메서드나 Bytes.fromHex 같은 타입 함수로 씁니다.

사용자 함수와 가져온 네임스페이스는 선언된 의미를 유지합니다. 이름 붙은 인수를 쓰는 호출은 원래 평가 순서대로 인수 식을 임시 값에 저장한 뒤 수신자를 옮기세요. 값으로 쓴 내장 함수는 타입을 명시한 람다로 옮깁니다.

v5 이전 소스 옮기기

v5 이전 토파즈 소스를 직접 고쳐 현재 문법으로 옮기세요. 기존 동작을 보존하고 변경할 때마다 결과를 비교하세요. 호환성을 유지하는 제품 업데이트에는 별도의 소스 이전이 필요하지 않습니다.

파일 하나 옮기기

다음 예전 코드는 구형 선언 문법과 배열 타입 표기를 사용합니다.

mut let 이름들: [string] = ["Ada"]
let 첫값 = 이름들[0]

아래 현재 문법으로 고친 코드를 작업 폴더의 from-pre-v5.tpz에 저장하세요.

TOPAZ
import std.io

let mut 이름들: Array<string> = ["Ada"]
let 첫값: Option<string> = 이름들.get(0)
io.writeLine("{첫값}")

그 폴더에서 다음 명령을 실행하세요.

BASH
topaz check from-pre-v5.tpz
topaz run from-pre-v5.tpz

검사는 종료 코드 0으로 끝납니다. 실행은 종료 코드 0으로 끝나며 다음 결과를 출력합니다.

출력
Some(Ada)

이름들.get(0)은 Option<string>을 반환합니다. 첫 원소가 있으므로 결과는 Some(Ada)입니다. 배열 범위를 벗어난 인덱스는 None을 반환합니다. 배열의 직접 인덱싱도 지원하며, 범위를 벗어나면 실행 오류가 납니다. 프로그램에 필요한 동작을 선택하세요.

예전 코드를 문서에 실을 때는 text 블록을 쓰세요. 현재 문법에는 topaz 블록을 사용하세요.

프로젝트를 고치기 전에 동작 기록하기

진입 파일, 모듈 루트, 입력, 예상 출력, 실행 오류, 파일·네트워크 작업을 기록하세요. 비교할 수 있도록 실행 결과도 보관하세요. Rust·JavaScript·프레임워크 문법으로 쓴 예제는 토파즈 소스와 구분하세요.

소스와 패키지 메타데이터를 현재 언어 모드에 맞게 고치세요. 패키지 설정은 패키지와 의존성을 참고하세요. 과거 문법은 클래식에서, 지금 쓸 표기는 현재 매뉴얼에서 확인하세요.

자주 나오는 표기 바꾸기

예전 표기현재 표기보존할 내용
mut let xlet mut x바인딩의 재대입 가능 여부
[T]Array<T>원소 타입
function(T) -> U(T) -> U매개변수와 반환 타입
[head, ...tail][head, ..tail]리스트 패턴의 나머지 원소
args: ...T...args: T가변 인수의 타입
익명 function(x: T) => expr매개변수, 결과, 캡처한 바인딩
s[i], s.lengths.scalars()와 명시적 문자열 API유니코드 스칼라 위치와 개수
백틱, ${expr}큰따옴표, {expr}문자열 내용과 보간

유니코드 스칼라는 유니코드 값 하나이며 바이트나 눈에 보이는 글자와 단위가 다를 수 있습니다. 인덱싱과 등록한 템플릿 태그는 문자열과 템플릿을 참고하세요. self는 현재 메서드 선언이 허용하는 위치에서 사용하세요.

복구할 수 있는 실패에는 Result를, 값이 없을 수 있을 때는 Option이나 null을 포함한 타입을 쓰세요. 실행 오류와 반환하는 오류 값을 구분하세요. 정리 작업은 defer나 지원하는 using 구문으로 옮기세요. import, export, 가시성, 초기화는 모듈과 가시성에 맞게 고치세요.

외부 언어 코드는 언어를 명시한 빌드·변환 단계에 두세요. 토파즈 모듈에 토파즈 문법처럼 붙여 넣을 수 없습니다.

고친 프로그램의 결과 비교하기

고친 소스에 topaz check를 실행한 뒤 프로젝트 테스트를 실행하세요. 위 파일은 출력이 Some(Ada)인지 비교하세요. 프로젝트에서는 기록한 입력과 결과를 비교하세요.

모듈 초기화, 순회 순서, 유니코드 스칼라 위치, 수식 계산 오류, 정리 작업, 허용한 호스트 작업을 확인하세요. 진단이 나오면 연결한 현재 문법을 참고해 소스 위치를 고치세요. 검사를 통과해도 출력이 다르면 같은 입력으로 바뀐 로직을 살펴보세요.

빌드 결과물을 따라 배포할 네이티브·Web·Worker 환경에 맞게 빌드하세요. 지원하지 않는 표기는 결과물 생성 전에 진단으로 알려야 합니다. 검사·테스트가 통과하고 선택한 각 빌드가 예상대로 동작하면 이전을 마칩니다.

관련 문서