장면 1 길 끝 화분
한줄이그런데 나를 검사해 준 도구는 누가 만들었어?
씨앗사람들이 만들었어.한줄아, 너를 검사한 컴파일러도 글로 쓴 프로그램이야.어떤 말로 썼는지 같이 읽어 볼래?
코드의 일생 06
컴파일러도 누군가 쓴 프로그램일까?
첫 바퀴의 친구들을 모두 만난 한줄이에게 마지막 궁금증이 남았어.
이번에는 한줄이를 검사해 준 도구 쪽을 들여다볼 차례야.
답은 지도 뒷면에 있어.
씨앗과 함께 펼쳐 보자.
한줄이그런데 나를 검사해 준 도구는 누가 만들었어?
씨앗사람들이 만들었어.한줄아, 너를 검사한 컴파일러도 글로 쓴 프로그램이야.어떤 말로 썼는지 같이 읽어 볼래?
한줄이어? 뒷면에 글이 가득해!
씨앗너를 검사한 컴파일러의 소스야.오늘은 그 첫 열 줄을 옮겨 왔어.
한줄이src/main.tpz? 내 파일 이름이랑 끝이 똑같아!
씨앗컴파일러의 설정 파일이 이 파일을 시작 파일로 적어 두었어.너처럼 이 파일도 토파즈로 썼어.
가지어, 이 낱말 어디서 본 것 같은데?
씨앗너희가 이 안에 사는 건 아니야.그래도 첫 바퀴에서 함께 본 일의 이름은 여기 적혀 있어.같이 찾아볼까?
뚝딱이지도 귀퉁이에 5.21.1이라고 쓰여 있네?
씨앗우리가 펼친 토파즈의 판 번호야.이 번호가 있으면 나중에도 어느 판의 소스를 읽었는지 알 수 있어.
이제 지도 뒷면을 직접 읽어 볼 차례야.
작은 실험
한줄이의 파일 이름은 main.tpz야.
토파즈 컴파일러의 설정 파일을 보니, 컴파일러의 소스도 src/main.tpz에서 시작한대.
이름 끝이 똑같네.
이번에는 컴파일러 쪽 파일의 첫 열 줄을 펼쳐 보자.
이 쪽은 컴파일러를 실행하지 않아. 뒷면의 글은 토파즈가 공개한 소스에서 그대로 옮겨 왔어.
main.tpz
1 + 26바이트 · 1줄 · 제1화부터 함께한 파일
src/main.tpz
16,891바이트 · 전체 560줄 가운데 첫 10줄 · 토파즈 5.21.1 공개 소스
토파즈 5.21.1 공개 소스
지도를 뒤집으면 뒷면에 무엇이 있을까?
import std.json as jsonBoundaryimport checker { check }import emitter { emitRust, emitStep }import layout { normalize }import lowering { lowerStep, lowerValue }import parser { parse }import profile { checkProfile }import raw { lex }import resolver { resolvePreview, resolveWithFacts }첫 바퀴에서 이 친구와 함께 본 일을 떠올려 봐. 어느 줄이 그 일을 하는 이름을 불러올까?
네 친구의 핀을 한 번씩 꽂아 보면 발견 카드가 열려.
import 줄을 보면 이 파일이 어디에서 어떤 이름을 가져오는지 알 수 있어.
조금 더 내려가면 lex(request.source)처럼 그 이름을 실제로 쓰는 자리도 있어.
네 친구의 줄
톡톡 9행 import raw { lex }
lex가 그 이름이야. lexical의 첫 세 글자와 같아. 전체 파일의 261행이 lex(request.source)로 소스를 넘기고, 바로 다음 줄이 raw.tokens를 꺼내 써.
가지 7행 import parser { parse }
parse가 그 이름이야. 구문 분석을 영어로 parsing이라고 해. 제2화에서 조각을 나무로 묶어 본 그 일이야.
타미 3행 import checker { check }
check가 그 이름이야. checker.tpz는 첫 주석에서 이 모듈의 일을 타입 검사로 설명해.
모모 6행 import lowering { lowerStep, lowerValue }
lowerStep과 lowerValue가 그 이름이야. 둘 다 제4화에서 카드로 옮겨 적어 본 로어링과 이어져.
import 줄도 읽어 보기std.json 모듈을 jsonBoundary라는 이름으로 불러와.emitter에서 두 이름을 불러와. 컴파일러는 emitRust를 호출해 Rust 코드를 만들어. 제4화에서 본 로어링의 이름은 어느 줄에 있을까?layout에서 normalize를 불러와. 262행에서 raw.tokens를 받아 쓰는 이름이야. normalize가 줄바꿈을 어떻게 다루는지 제7화에서 보기profile에서 checkProfile을 불러와. 여기에도 check가 보이네. 제3화에서 본 타입 검사를 맡은 checker 모듈은 어느 줄에서 불러올까?resolver에서 resolvePreview와 resolveWithFacts를 불러와. resolve는 이름이 무엇을 가리키는지 찾는다는 뜻이야.컴퓨터는 설치된 topaz 파일을 실행해. 우리가 지금 읽는 글은 토파즈가 따로 공개한 소스야.
설정 파일 topaz.toml에 entry = "src/main.tpz"라고 적혀 있어.
여기에는 전체 560줄 가운데 첫 10줄만 옮겨 왔어. 전체 파일은 공식 소스 압축에 들어 있어.
topaz-source-snapshot-v5.21.1.tar.gzd3a0e5365b8a39605f095a7c07b43556848a95042e7efd346ab84c95e583cf3dcompiler/crates/topaz_self_frontend/topaz/src/main.tpzef16cb39e9956e7e3aaed8023f9a45388c49a17bd9336a6e6f29dfa5aeb63bd3옮겨 온 소스는 같은 판의 라이선스와 고지를 따라. LICENSE 읽기, 새 창 NOTICE 읽기, 새 창
지도와 핀은 이야기 속 그림이야. 뒷면의 글과 숫자는 공개된 원문에서 왔어.
진짜 속사정
지도 뒷면에 옮겨 적은 글은 컴파일러의 소스 코드야. 한줄이처럼 누군가 글로 써 둔 프로그램이지.
토파즈 문서는 기본 컴파일러는 토파즈로 작성했습니다.라고 적어 두었어. 툴체인 상태 문서, 새 창
자기가 번역하는 언어로 작성되어 자기 소스도 컴파일할 수 있는 컴파일러를 셀프호스팅 컴파일러라고 해.
이 컴파일러의 폴더에는 .tpz 파일이 50개 있어. 시작 파일 main.tpz는 560줄이고, 한줄이의 main.tpz는 한 줄이야.
컴파일러 안에서도 let으로 값에 이름을 붙여. 261행에는 let raw = lex(request.source)가 있고, 바로 다음 줄이 그 raw.tokens를 꺼내 써.
제1화부터 제4화에서 본 토큰, 나무, 타입, 작업 기록은 토파즈 5.21.1의 기본 컴파일러로 남겼어. 오늘 펼친 건 바로 그 컴파일러의 공개 소스야.
옮겨 온 소스는 같은 판의 라이선스와 고지를 따라. LICENSE 읽기, 새 창 NOTICE 읽기, 새 창
아니. 친구들은 이야기 속 모습이야. 컴파일러는 일을 여러 파일과 이름으로 나눠 적고, 그 가운데 첫 바퀴에서 본 일과 닮은 이름이 있을 뿐이야.
3행부터 10행까지의 import 줄은 모듈 이름의 낱말 차례로 놓여 있어. 일하는 차례와는 달라. 일을 나누는 방법과 차례는 컴파일러마다 다를 수 있어.
아니. 어떤 컴파일러는 자기가 번역하는 언어로 쓰고, 어떤 컴파일러는 다른 언어로 써.
토파즈 5.21.1 기록과 공개 소스
더 들여다보기
기록에 적힌 것 토파즈 5.21.1에 상태를 물으면 기본 컴파일러와 참조 컴파일러를 따로 적어.
Default compiler: self
Reference compiler: rust기록에 적힌 것 기본 컴파일러에는 self, 참조 컴파일러에는 rust라고 적혀 있어.
토파즈 문서는 같은 입력의 결과를 견주어 볼 때 이 참조 컴파일러를 쓰는 예를 보여 줘., 새 창
기록에 적힌 것 1 + 2를 세 번 검사했어. 쪽지 받침에는 어느 컴파일러를 골랐는지 적혀 있어.
명령topaz check -v main.tpz
쪽지 받침topaz: compiler selection: self (current-default)
main.tpz: types-ok (1 module)
main.tpz: resolve-ok (1 module)명령topaz check -v --compiler self main.tpz
쪽지 받침topaz: compiler selection: self (explicit)
main.tpz: types-ok (1 module)
main.tpz: resolve-ok (1 module)명령topaz check -v --compiler rust main.tpz
쪽지 받침topaz: compiler selection: rust (explicit)
main.tpz: types-ok (1 module)
main.tpz: resolve-ok (1 module)기록에 적힌 것 아무것도 고르지 않은 검사에는 current-default, 이름을 붙여 고른 검사에는 explicit이라고 적혀.
이 사이트가 맞대 본 것 화면 창의 두 줄은 세 번 모두 바이트까지 같았어.
두 컴파일러가 같은 일을 하는지 나란히 견주는 건 더 먼 바퀴의 몫이야.
제4화에서 모모의 카드를 남긴 1 + 2 관측에는 provenance.json이라는 출처 파일도 있어.
기록에 적힌 것 제4화 출처에는 생성한 Rust가 연이은 두 단계에서 바이트까지 같았다고 적혀 있어.
기록에 적힌 것 중간 기록의 고정점은 성립했다고 적혀 있지 않아.
기록에 적힌 것 실행 파일의 바이트 대조에는 아직 돌리지 않았다는 값이 있어.
기록에 적힌 것 이 컴파일러의 링크 도구 기록에는 rustc 1.96.0이 적혀 있어.
이 사이트가 맞대 본 것 5.21.0 판과 5.21.1 판의 출처 기록에서 고른 아홉 항목의 값이 같았어. 두 출처 파일의 전체 바이트는 달랐어.
토파즈 5.21.1의 컴파일러 씨앗은 압축 꾸러미 하나와 그 목록으로 공개돼 있어.
이 사이트가 맞대 본 것 씨앗 꾸러미에는 토파즈로 쓴 컴파일러 소스, 거기서 생성한 Rust, 함께 쓰는 런타임 코드와 빌드 스크립트가 있어.
이 사이트가 맞대 본 것 설치된 컴파일러의 출처와 씨앗 목록에서 식별자 셋이 맞았어.
이 사이트가 맞대 본 것 꾸러미에서 꺼낸 Rust 파일의 해시도 목록에 적힌 값과 같았어.
topaz-bootstrap-seed-v5.21.1.tar.gzcf6a09b66fa5197472808fc01388e799b394686fb705b8e977cc39962583e974맞대 본 식별자 셋
compiler.sourceSetIdsha256:17d598ebcb0dea65195aba8c0b3ab20f94003a7f343714f7b1df25d790cdacd5sourceReuse.compilerSourceSetIdsha256:17d598ebcb0dea65195aba8c0b3ab20f94003a7f343714f7b1df25d790cdacd5compiler.runtimeSourceSetIdsha256:85ed8d3b0571c34bc40c3ffd1be8bcda2a539d6c82c92b417c834507200d9c60sourceReuse.runtimeSourceSetIdsha256:85ed8d3b0571c34bc40c3ffd1be8bcda2a539d6c82c92b417c834507200d9c60compiler.generatedRustSha256sha256:5f32cee07a1adea1c67ba8ac8fbd4f3ee4051f019a7856fcdb228740a1d4b8b1sourceReuse.generatedRustSha256sha256:5f32cee07a1adea1c67ba8ac8fbd4f3ee4051f019a7856fcdb228740a1d4b8b1꾸러미에서 꺼낸 파일로 다시 구한 해시 generated/compiler.rs 5f32cee07a1adea1c67ba8ac8fbd4f3ee4051f019a7856fcdb228740a1d4b8b1
이번에 사이트가 한 일은 여기까지야.
이 사이트가 맞대 본 것 5.21.0 판과 5.21.1 판의 씨앗 목록에서 컴파일러의 .tpz 파일 50개를 같은 경로끼리 맞대 봤어. 아홉 파일의 해시가 달랐어. 우리가 펼친 src/main.tpz의 해시는 두 판에서 같았어.
해시가 달랐던 파일
checker/call_complete.tpzchecker/call_facts.tpzchecker/expression_control.tpzchecker/expression_core.tpzchecker/members_capabilities.tpzchecker/statements.tpzchecker/type_algebra.tpzemitter/emit.tpzresolver/scopes_walk.tpz기록에 적힌 것 발행자는 씨앗 꾸러미를 빌드했는지 built에, Rust를 다시 만들었는지 regenerated에 적어 두었어.
builttrueregeneratedtrue기록에 적힌 것 씨앗의 안내문은 이렇게 적어. The compiler written in Topaz performs parsing, checking, lowering and Rust generation.
다음 바퀴에서 물어볼 것
다시 만든 Rust는 꾸러미에 든 Rust와 바이트까지 같을까?
옮겨 온 소스는 같은 판의 라이선스와 고지를 따라. LICENSE 읽기, 새 창 NOTICE 읽기, 새 창
한 줄 정리
컴파일러도 누군가 어떤 언어로 써 놓은 프로그램이야.
한줄이를 검사한 토파즈의 기본 컴파일러는 토파즈로 썼어.
씨앗이 펼친 src/main.tpz가 컴파일러의 시작 파일이라는 건 어디에서 찾았을까?
설정 파일 topaz.toml에 entry = "src/main.tpz"라고 적혀 있어.
그 길을 따라가서 컴파일러를 쓴 토파즈 코드를 읽었어.
이제 컴파일러를 보면 그 뒷면의 소스도 떠오르겠지?
속사정 도감낱말 다시 보기컴파일러셀프호스팅 컴파일러
돌아보기
톡톡과 1 + 2를 조각으로 나눠 봤어.
가지와 더하기의 두 수가 나무에서 어디에 붙는지 봤어.
제2화 다시 읽기타미와 1 + "사과"에서 타입 검사가 왜 멈췄는지 읽었어.
모모의 작업 카드에서 1 + 2의 두 수를 다시 찾았어.
뚝딱이와 출력하는 줄을 넣은 프로그램의 기록을 읽었어. 화면 창에 시작과 3이 차례로 남았어.
씨앗과 지도를 뒤집어, 우리 코드를 검사한 컴파일러의 소스를 펼쳐 봤어.
첫 바퀴에서는 토파즈 5.21.1로 1 + 2와 몇 가지 다른 예를 살펴봤어.
다음 바퀴는 톡톡의 정거장에서 새 질문으로 시작해.
다음 이야기
톡톡나 아직 할 말이 남았어. 빈칸 이야기야.
길의 첫 정거장에서 톡톡이 가위를 다시 들었어.
빈칸과 줄바꿈은 언제 뜻이 될까?
다음에는 첫 정거장으로 돌아가 보자.