Skip to content

달빛약속의 일곱 번째 대보름 ​

어쩌다보니 명절마다 메이저 업데이트를 하는 기분이 드네요. 여섯 번째 대보름은 올 설에 공개하였고, 일곱 번째 대보름은 추석에 작업해서 일주일 뒤인 오늘 공유드립니다. 사실 기분 좋은 릴리즈는 아니라는 점에 먼저 사과를 드립니다. API도 많이 바뀌었고, 삭제된 문법/기능들도 적지 않고, 내부 구현도 무척 많이 바뀌었습니다.

한 잔은 떠나간 기능을 위하여 ​

  • 문법: 클래스, 람다, 파이썬 호환 문법, 점 접근자 메소드가 삭제되었습니다.
  • API: Step By Step Execution, Running Code, Machine Readable Errors가 삭제되었습니다.
  • 확장: Monaco 언어 지원이 삭제되었습니다.

삭제를 결정한 근거는 다음과 같습니다:

  1. 이 기능이 있어야만 달빛약속이 학습자에게 더 쉬워질까?
  2. 이 코드를 없애면 학습자에게 도움이 될 기능을 개발하는게 더 빨라질까?

추가 의견은 언제나 환영입니다.

한 잔은 새로운 함수 문법을 위하여 ​

이벤트 다음으로 추가되는 큰 문법인 것 같습니다. 사실 RC.2 릴리즈 노트에 이미 작성되어 있었어서 .. 처음 말씀드리는 것은 아닙니다.

약속, 이동하기(가로, 세로)
    "가로로 {가로}, 세로로 {세로} 만큼 이동해요" 보여주기

이동하기
    세로: 60
    가로: 50

블록으로 함수를 호출하는 문법이 추가되었습니다. 마지막에 인자가 몰리도록 선언된 함수에서 사용할 수 있습니다.

원래는 복잡한 함수는 이렇게 난해해보였으나

약속, 속도 왼쪽 (왼쪽_속도) 오른쪽 (오른쪽_속도)로 설정하기
    # ...

속도 왼쪽 10 오른쪽 20로 설정하기

새로운 문법을 사용하면 다음과 같이 작성할 수 있습니다.

약속, 속도 설정하기(왼쪽, 오른쪽)
    # ...

속도 설정하기
    왼쪽: 10
    오른쪽: 20

없어도 되는 인자의 뒤에는 ?를 붙혀서 선택형임을 나타냅니다.

약속, 속도 설정하기(왼쪽, 오른쪽, 기어?)
    # ...

속도 설정하기
    왼쪽: 10
    오른쪽: 20

이러면 기어 인자는 있어도 되고 없어도 됩니다. 주어지지 않은 인자에 대해서는 비어있음(EmptyValue)라는 값으로 설정됩니다.

EmptyValue가 뭔가요 Optional Parameter를 위해 새롭게 추가된 Primitive입니다. Falsy하게 평가되고, EmptyValue가 아닌 다른 값들과의 동일성 비교는 항상 Falsy입니다. stdout으로는 '비어있음'으로 출력됩니다.

한 잔은 달라진 실행 흐름을 위하여 ​

기존 코드는 준비, 실행, 결과가 명확히 분리되지 않아서 흐름 이해에 어려움이 있었습니다. 이제 각 구성요소가 다음과 같이 역할을 분담합니다:

  • Session: 코드파일 여러개 묶음
  • CodeFile: 파싱 결과를 담음
  • Scope: 실행 결과를 담음

명확히 역할을 나누기 위해 일부 실행 컨셉이 변경됩니다:

  • 상위 Scope에서 정의된 함수를 실행할 수 있도록, Scope가 동적패턴을 가집니다.
  • 실행이 종료된 Scope는 재사용할 수 없습니다. finialize 필드가 추가되어서, 이미 죽어서 동결된 스코프는 읽기 전용입니다.
  • BaseContext라는 이름의 모호함을 해소하기 위해 Base Scope라는 이름으로 개칭하였습니다. 이름에 맞게 실제로 CodeFile이 아니라 Scope를 인자로 받습니다.
  • CodeFile은 항상 Session에 소속됩니다.
  • Scope/Error는 CodeFile이 아니라 Session과 더 긴밀한 관계를 맺습니다.

한 잔은 오버홀에서 살아남은 코드를 위하여 ​

재건축.. 재건축.. 까지는 아니지만 리모델링 수준의 개보수 작업을 진행하였습니다.

  1. 코드베이스가 절반 이상으로 줄었음. 기존엔 4.1만줄이였는데 이젠 1.7만줄입니다.
  2. 파일 하나를 제외하고 모든 파일이 적어도 한 글자 이상 바뀌었습니다.

동시에 파싱 속도도 무진장 빨라졌습니다.

  • 수식만 있는 코드: 6배 빨라짐
  • 약속을 선언한 코드: 15배 빨라짐
  • 약속도 선언하고 조사 변형도 하는 코드: 25배 빨라짐
  • 함수 호출도 하는 코드: 18배 빨라짐

평균적으로 파싱 속도가 자릿수 하나만큼 줄어든 것 같습니다. 이제 매 키 입력 마다 파싱을 해도 될 것 같습니다. (사실 매 키 입력마다 파싱 하려고 개선 작업 진행했습니다.)


다음의 계획 ​

  1. Mention 문법을 파일 임포트가 아니라 객체지향의 일부로 활용해볼까 싶습니다. 클래스의 재림은 아닙니다.
  2. CodeMirror 에디터를 만들 예정입니다.

요즘의 고민 ​

1. Shift-Reduce 파서의 한계가 보입니다. ​

자연어 문법과 유사하게 동적생성을 해야 해서 결합력 기반의 파서는 난해해지고..하니까 SR 파서로 구현을 하였는데, 수식-함수 구분선이나 파싱 실패 오류메시지같은걸 후처리 할 때, 슬슬 한계를 느낍니다. 재귀하강 파서로의 마이그레이션을 고려해볼 수 있을 것 같은데, 워낙 큰 작업이라서 가능할 지는 모르겠습니다.

2. 도대체 AI 어떻게 써야 할지 모르겠습니다. ​

제가 그렇게 성실하지 않은 탓인지.. AI가 짜준 코드를 이해할 의향이 도저히 나지 않고.. 이해를 하는데 드는 시간이 내가 직접 짜는 시간보다 더 오래 걸리는 것 같습니다. 인터프리터는 모든 실행 요소가 한번에 굴러가다 보니 그림이 머릿속에 들어있지 않으면 오류가 나도 파악하기가 어려워서.. 도저히 어떻게 써먹어야 할 지 모르겠습니다. 그래서 v6에서 v7 갈 때는 코드리뷰/단순 리팩토링 제외하고는 다 손코드로 적었습니다.


그 외 .. ​

  • 그 어떤 매칭 라이브러리도 제 성에 차지 않아서 @dalbit-yaksok/pattern이라는 매칭 라이브러리를 새로 만들었습니다. 파싱 속도 개선은 이 라이브러리 덕도 있습니다. Valibot보다 빠르고 ts-pattern만큼 우아합니다.
  • 욕심이 많아서 릴리즈가 좀 오래 걸렸습니다. 거의 몇 주 동안 작업한 것 같습니다.