# Five — 개발 규칙 ## 절대 규칙: 변경 후 반드시 검증 **어떤 파일이든 수정한 후, 다음 3개 테스트를 모두 통과해야 한다.** 하나라도 실패하면 해당 변경을 되돌린다. ```bash # 1. Go 유닛 테스트 go test ./... # 2. FiveSql2 SQL 테스트 (43/43) ./five build _FiveSql2/test/test_sql1999.prg _FiveSql2/src/*.prg -o /tmp/test_sql cd ~/tmp && rm -f *.dbf __cte_*.dbf && /tmp/test_sql # 3. Harbour 호환 테스트 (51/51) ./five build tests/compat_harbour.prg -o /tmp/test_compat && /tmp/test_compat ``` **절대로 "나중에 확인" 하지 않는다. 매 변경마다 즉시.** --- ## 파일별 영향 범위 수정하는 파일에 따라 어디가 깨질 수 있는지: ### hbrt/ (런타임 — 가장 위험) | 파일 | 변경 시 영향 | 주의사항 | |------|------------|---------| | thread.go | **모든 것** | Frame/EndProc/Local 수정 시 FiveSql2 전체 crash 가능. EndProc은 반드시 re-panic 방식 유지 | | ops_arith.go | 모든 산술/FOR 루프 | LocalAdd/LocalAddInt는 byref-aware 필수 | | ops_compare.go | 모든 비교/IF/WHILE | PopLogical은 NIL→false 유지. LocalLessEqualInt는 byref-aware 필수 | | ops_collection.go | 배열/해시 접근 | ArrayPush/ArrayPop은 hash + string 인덱싱 지원 필수 | | value.go | **모든 것** | Value 구조체 크기(24B) 변경 금지. HbRefCell은 ptr 필드 사용 | | call.go | 모든 함수 호출 | Function()의 pop/push 순서 변경 금지. copy 최적화 시도 금지 (이전에 실패) | | class.go | 모든 메서드 호출 | Send()의 pendingParams 설정 순서 유지 | ### compiler/gengo/ (코드 생성 — 두 번째로 위험) | 파일 | 변경 시 영향 | 주의사항 | |------|------------|---------| | gengo.go | 모든 생성 코드 | emitExpr의 BinaryExpr: short-circuit AND/OR 유지. emitBlock: RefCell 기반 mutable capture 유지. emitAssignExpr: 블록 내 += 처리 필수 | | gen_class.go | 클래스/메서드 | blockSeq는 함수 간 공유됨 (reset 불필요) | | gen_cmd.go | USE/INDEX 등 명령 | USE ALIAS (expr) 동적 별칭 유지 | ### hbrtl/ (RTL 함수) | 파일 | 변경 시 영향 | 주의사항 | |------|------------|---------| | array.go | AEval/ASort/AScan | AEval: push 순서 = index먼저, element나중 (Frame이 상단에서 가져감) | | database.go | DB 함수 전체 | dbUseArea 실패 시 반드시 *HbError panic | | register.go | 함수 등록 | 새 함수 추가 시 이름 충돌 확인 | ### _FiveSql2/src/ (SQL 엔진 PRG) | 파일 | 주의사항 | |------|---------| | TSqlExecutor.prg | 세미콜론 인라인 `IF...ENDIF` 사용 금지 (Five 파서 미지원). ENDIF 개수 반드시 IF와 매칭 확인 | | TSqlDDL.prg | @byref 미지원이었으나 이제 동작함. MemoRead 사용 유지 | | TFiveSQL.prg | Query Plan Cache: parse tree가 실행 중 변경됨(aTables 등). 캐시 시 deep clone 필수 | --- ## 알려진 제약사항 | 항목 | 상태 | 비고 | |------|------|------| | CDX 바이너리 Harbour 호환 | ⚠️ CHAR 태그만 호환 | 숫자 키: Harbour는 IEEE double 8B, Five는 DBF ASCII. Five↔Five 완벽 동작. Harbour가 Five CDX 읽기 시 숫자 태그에서 corruption | ### 해결된 제약 (2026-04-11~13) | 항목 | 커밋 | |------|------| | 세미콜론 IF...ENDIF | 이미 동작 확인 (2026-04-13) | | `{||}` / `{=>}` 함수 인자 파싱 실패 | 빈 블록 body에 NIL 리터럴 emit | | CDX compound index 쓰기 미지원 | CDX 빌더 구현 (비트팩 리프+compound root) | | STATIC inside FUNCTION → panic | `5bfdc47` — Go 패키지 변수로 emit | | FIELD->NAME 빈 값 반환 | `e95afad` — GetAliasField 반환 타입 수정 | | OrdSetFocus(n) 무동작 | `e95afad` — 숫자→문자열 변환 수정 | | Break("string") RECOVER USING panic | `3adc9d7` — BreakValue duck-type dispatch | | SET INDEX TO a, b, c 마지막만 열림 | `3adc9d7` — 파서+gengo 다중 파일 지원 | | PCount() 항상 0 반환 | `3adc9d7` — CallerParamCount + Frame.paramCount | | OutStd()/OutErr() 미등록 | `e95afad` — RTL 등록 | | Date + Numeric panic | `6c53747` — NumInt→Numeric 확장 | | STATIC += / -= 단순 대입으로 처리 | `5bfdc47` — compound assign 지원 | --- ## 최적화 시 주의 1. **thread.go의 pop() slot clearing** — 제거하면 stale 데이터 문제 가능. 현재 `cachedNil`로 클리어 유지 2. **call.go의 copy 최적화** — 이전에 시도했으나 pendingSyms desync 발생. 시도 금지 3. **growStack/growFrame 분리** — 가능하지만 다른 변경과 동시 적용 금지. 단독 적용 + 전체 테스트 4. **FiveSql2 PRG 최적화** — 한 번에 하나씩. Column Binding, CTE in-memory 등은 별도 브랜치에서 --- ## 빌드 환경 - `/mnt/d/` (NTFS 9P): 5~15x 느림. 벤치마크는 반드시 `~/tmp/` (ext4)에서 실행 - Five 컴파일러: `go build -o five ./cmd/five` - FiveSql2: 다중 파일 빌드 필수 `./five build test.prg src/*.prg -o output` - Go 경로: `export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin` --- ## 현재 지표 (2026-04-13) - Go test: ALL PASS (14 packages) - RTL 함수: 483개 - FiveSql2: 43/43 (100%) - Compat: 51/51 (100%) - Syntax test: 100/100 - RDD test: 44/44 - RTL test: 114/114 - Harbour RDD parity: diff 0 (281-line NTX+CDX comparison) - Windows cross-compile: OK (five.exe 4.0MB) - Linux cross-compile: OK (five_linux 3.8MB) - @byref: 동작 (RefCell) - Mutable closure: 동작 (RefCell + EnsureLocalRef) - FIELD->NAME: 동작 (읽기/쓰기) - STATIC inside FUNCTION: 동작 (패키지 변수 + 함수 스코프 격리) - PCount(): 동작 (CallerParamCount) - Break/RECOVER USING: 동작 (BreakValue duck-type) - 파일 락킹: POSIX fcntl + Windows LockFileEx - INDEX 성능: Harbour 대비 12% faster (50k records)