7. 확장 시스템: '달빛 약속'의 유연한 확장
'달빛 약속'은 자체적인 문법과 실행 환경을 가지고 있지만, 외부 세계, 특히 JavaScript/TypeScript의 풍부한 생태계와 상호작용할 수 있도록 설계되었습니다. 이러한 상호작용을 가능하게 하는 것이 바로 **확장 시스템(Extensions System)**입니다. 이 시스템은 '달빛 약속'의 기능을 유연하게 확장할 수 있는 강력한 도구입니다. 이번 장에서는 확장 시스템이 어떻게 동작하는지 자세히 알아보겠습니다.
확장 시스템의 목적: FFI(Foreign Function Interface) 및 미래
확장 시스템의 주된 목적은 현재 **FFI(Foreign Function Interface)**를 제공하는 것입니다. FFI는 한 프로그래밍 언어로 작성된 코드가 다른 프로그래밍 언어로 작성된 코드를 호출할 수 있도록 하는 메커니즘을 의미합니다. '달빛 약속'에서는 이를 통해 외부 JavaScript/TypeScript 코드를 '달빛 약속' 코드 내에서 실행하고, 그 결과를 다시 '달빛 약속'의 값으로 받아올 수 있습니다.
하지만 확장 시스템의 잠재력은 FFI에만 국한되지 않습니다. 미래에는 새로운 문법 요소 추가, 내장 함수 확장, 심지어 언어의 핵심 동작 방식 변경 등 더욱 다양한 형태의 확장을 지원할 수 있도록 설계될 예정입니다.
Extension
인터페이스 분석
확장 시스템의 핵심은 /core/extension/extension.ts
에 정의된 Extension
인터페이스입니다. 새로운 확장을 만들려면 이 Extension
인터페이스를 구현하는 클래스를 작성해야 합니다.
Extension
인터페이스는 다음과 같은 주요 멤버를 가집니다.
manifest: ExtensionManifest
: 확장의 메타데이터를 정의합니다. 특히ffiRunner
속성을 통해 이 확장이 어떤 FFI 런타임(runtimeName
)을 제공하는지 명시합니다. 예를 들어, QuickJS 확장은runtimeName: 'QuickJS'
를 가질 수 있습니다.init?(): Promise<void> | void
: 확장이 초기화될 때 호출되는 선택적 메소드입니다. 비동기 작업(예: 외부 라이브러리 로드, 환경 설정)이 필요한 경우 여기에 구현합니다.executeFFI(code: string, args: FunctionInvokingParams): ValueType | Promise<ValueType>
: 이 메소드가 바로 FFI의 핵심입니다. '달빛 약속' 코드에서 외부 함수 호출이 발생했을 때, 이 메소드가 호출되어 실제 외부 코드를 실행합니다.code
: 외부 런타임에서 실행할 코드 문자열입니다.args
: '달빛 약속' 코드에서 외부 함수로 전달된 인자들입니다. 이 인자들은 이미 '달빛 약속'의ValueType
형태로 변환되어 전달됩니다.- 반환 값:
executeFFI
메소드는 외부 코드의 실행 결과를 반드시 '달빛 약속'의ValueType
형태로 반환해야 합니다. 이를 통해 외부에서 계산된 값이 '달빛 약속' 환경으로 자연스럽게 통합될 수 있습니다.
YaksokSession
과의 연동
Extension
인스턴스는 YaksokSession
과 긴밀하게 연동됩니다.
확장 등록:
YaksokSession
의extend(extension: Extension)
메소드를 통해Extension
인스턴스를 세션에 추가합니다. 세션은 등록된 확장들을 내부적으로 관리합니다.typescriptconst session = new YaksokSession() await session.extend(new QuickJS()) // QuickJS 확장을 세션에 등록
FFI 호출 처리: '달빛 약속' 코드 내에서
@확장명
문법을 사용하여 외부 함수를 호출하면, 실행기(Executer
)는YaksokSession
의runFFI
메소드를 호출합니다.YaksokSession
의runFFI(runtime: string, code: string, args: Record<string, any>): Promise<ValueType>
메소드는 다음과 같은 역할을 합니다.runtime
이름(manifest.ffiRunner.runtimeName
)을 기반으로 등록된Extension
을 찾습니다.- 찾은
Extension
의executeFFI
메소드를 호출하여 실제 외부 코드를 실행합니다. executeFFI
의 반환 값을 받아 '달빛 약속'의ValueType
으로 변환하여 '달빛 약속' 코드에 전달합니다.
FFI의 실제 용례: QuickJS 확장
'달빛 약속' 프로젝트에는 /quickjs
디렉터리에 QuickJS 런타임을 활용한 FFI 확장이 구현되어 있습니다. 이 확장은 Extension
인터페이스를 구현하여 '달빛 약속' 코드 내에서 JavaScript 코드를 실행할 수 있도록 합니다.
const session = new YaksokSession()
await session.extend(new QuickJS())
session.addModule(
'main',
`
번역(QuickJS), (배열) 중 최대값
***
return Math.max(...배열)
***
번역(QuickJS), (배열)에서 가장 큰 값 제거하기
***
const n = 배열.indexOf(Math.max(...배열))
return [...배열.slice(0, n), ...배열.slice(n + 1)]
***
내_점수 = [80, 90, 100]
내_점수 중 최대값 보여주기
내_점수 = 내_점수 에서 가장 큰 값 제거하기
내_점수 보여주기
내_점수 중 최대값 보여주기
`,
)
const result = await session.runModule('main')
이처럼 확장 시스템은 '달빛 약속'이 특정 환경이나 기능에 갇히지 않고, 외부의 풍부한 생태계를 활용할 수 있도록 하는 강력한 도구입니다.