Files
five/docs/harbour-go-evolution-strategy.md
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

34 KiB

Five: Harbour + Go 융합 전략

단순 포팅이 아닌, Harbour의 비즈니스 로직 표현력과 Go의 현대적 생태계를 융합하여 새로운 개발 플랫폼으로 진화시키는 전략 문서

Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) All rights reserved.


목차

  1. 현재 문제 진단
  2. 비전: 왜 Go인가
  3. 설계 철학: 단순 포팅이 아닌 융합
  4. Go 생태계 직접 연동
  5. 동시성 모델 진화
  6. 네트워크 네이티브
  7. 멀티플랫폼 전략
  8. RDD 진화: DBF를 넘어서
  9. 언어 진화 제안
  10. 기존 코드 마이그레이션
  11. 생태계 구축 전략
  12. 아키텍처 총괄
  13. 로드맵

1. 현재 문제 진단

Harbour 생태계의 구조적 한계

문제 1: 생태계 정체
  - 주요 기여자 수: ~5명 활동
  - 최근 커밋 빈도: 월 1-2회
  - 새로운 라이브러리/프레임워크: 거의 없음
  - 패키지 매니저: 없음
  - 결과: 개발자가 모든 것을 직접 구현해야 함

문제 2: 현대 기술 접근 불가
  - HTTP/REST API: contrib에 기본적인 것만
  - JSON/XML: 제한적
  - WebSocket: 없음
  - gRPC: 없음
  - 클라우드 SDK: 없음
  - 컨테이너/k8s: 고려되지 않은 설계

문제 3: 스레딩의 고질적 결함
  - 글로벌 상태 + 수동 mutex → 레이스 컨디션
  - GC suspend 모델 → 불안정
  - 실무에서 MT 모드 회피 경향

문제 4: 배포/운영
  - C 런타임 의존성
  - 플랫폼별 빌드 설정 복잡
  - 크로스 컴파일 어려움
  - 컨테이너 이미지 대형화

문제 5: 개발 도구
  - LSP/DAP: 없음
  - 코드 포매터: 없음
  - 린터: 없음
  - IDE 지원: 구문 강조 수준

Harbour의 핵심 강점 (보존 대상)

강점 1: xBase 명령어의 데이터 처리 표현력
  USE customers
  SET FILTER TO age > 30
  INDEX ON lastname + firstname TO cust_name
  SEEK "SMITH"
  REPLACE salary WITH salary * 1.1

  → SQL보다 절차적이고, 일반 코드보다 선언적
  → 비즈니스 로직을 매우 간결하게 표현

강점 2: 매크로 시스템의 동적 유연성
  cField := "salary"
  REPLACE &cField WITH &cField * 1.1
  → 런타임 코드 생성, 동적 비즈니스 규칙 엔진에 강력

강점 3: 코드 블록의 함수형 표현
  aData := { {1,"A"}, {2,"B"}, {3,"C"} }
  ASort(aData, {|x,y| x[2] < y[2] })
  AEval(aData, {|x| QOut(x[2]) })

강점 4: 검증된 대량 레거시 코드베이스
  → 수십 년 운영된 비즈니스 로직
  → 재작성 불가, 점진적 마이그레이션 필수

2. 비전: 왜 Go인가

Go가 Harbour의 약점을 정확히 보완

Harbour 약점              Go 강점                    결합 효과
─────────────            ──────────                  ─────────
생태계 정체               60,000+ 패키지             Go 패키지 직접 사용
스레딩 결함               goroutine + channel        구조적 동시성
네트워크 부재             net/http, gRPC 내장        HTTP/API 네이티브
배포 복잡                 단일 바이너리 + 크로스컴파일  어디서든 실행
개발 도구 부재            gopls, delve 참조 가능      LSP/DAP 구현 용이
클라우드 미지원           K8s/Docker 네이티브        컨테이너 최적화
패키지 관리 없음          go modules                 의존성 관리 해결

Five가 Go에 더하는 가치

Go의 약점                Five가 보완               결합 효과
──────────              ────────────              ──────────
class 문법 없음          CLASS/ENDCLASS 지원       OOP 직관적 표현
  struct+interface       상속, 다형성, 연산자 오버로딩
  메서드가 분산 정의      클래스 안에 응집

제네릭 제한적            동적 타이핑 유연성         타입에 구애받지 않는 코드
  Go 1.18+이나 복잡      ANY 타입 자연스러움

enum 없음               xBase 표현력              비즈니스 로직 간결
  iota 패턴 불편         SWITCH TYPE, 매크로

REPL 없음               harbour repl              빠른 프로토타이핑
  컴파일 필수            대화형 탐색

DSL 표현력 부족          xBase 명령어              데이터 처리 선언적
  USE/SEEK/REPLACE       SQL보다 절차적이면서
  같은 표현 불가         일반 코드보다 선언적

핵심: Five는 Go에 class와 xBase DSL을 얹어주는 것이다.

Go 개발자 관점에서 Five의 CLASS:

// Five: 하나의 블록에 데이터 + 메서드가 응집
CLASS HttpClient
   DATA cBaseUrl   INIT ""
   DATA nTimeout   INIT 30
   DATA oHeaders   INIT {=>}

   METHOD New(cUrl)
   METHOD Get(cPath)
   METHOD Post(cPath, hBody)
   METHOD SetHeader(cKey, cVal)
ENDCLASS

METHOD New(cUrl) CLASS HttpClient
   ::cBaseUrl := cUrl
   RETURN Self

METHOD Get(cPath) CLASS HttpClient
   // net/http를 내부에서 사용
   RETURN hbhttp.Get(::cBaseUrl + cPath, ::oHeaders)

METHOD SetHeader(cKey, cVal) CLASS HttpClient
   ::oHeaders[cKey] := cVal
   RETURN Self

// 사용: 메서드 체이닝
LOCAL oApi := HttpClient():New("https://api.example.com")
oApi:SetHeader("Authorization", "Bearer " + cToken)
LOCAL hData := oApi:Get("/users")
// 동일한 것을 순수 Go로 작성하면:
// 구조체 정의와 메서드가 분산됨
type HttpClient struct {
    BaseUrl  string
    Timeout  int
    Headers  map[string]string
}

func NewHttpClient(url string) *HttpClient { ... }  // 별도 위치
func (c *HttpClient) Get(path string) { ... }       // 별도 위치
func (c *HttpClient) Post(path string) { ... }      // 별도 위치
func (c *HttpClient) SetHeader(k, v string) { ... } // 별도 위치
// → 클래스 개념이 파일 전체에 흩어짐

다른 언어가 아닌 이유

대안 기각 사유
Rust 학습 곡선 극도로 높음, Harbour 사용자층과 부적합
Java/Kotlin JVM 의존, 단일 바이너리 불가, 시작 시간
Python 성능, GIL 문제, 타입 안전성
C# (.NET) MS 종속성, 리눅스 배포 복잡
Node.js 단일 스레드, 타입 안전성, 바이너리 배포
Go 단일 바이너리, goroutine, 거대 생태계, 학습 용이, 크로스컴파일

3. 설계 철학: 단순 포팅이 아닌 융합

기존 접근 (단순 포팅) — 이것을 하지 않는다

PRG → [Harbour 컴파일러 Go 포팅] → [Harbour VM Go 포팅] → 실행
       ↑                            ↑
       C 코드를 기계적으로           C 구조를 그대로
       Go로 번역                    Go로 재현

결과: Go로 작성된 Harbour일 뿐
     Go 생태계 활용 불가
     새로운 가치 없음

채택 접근 (융합) — Five

PRG → [Five 컴파일러] → Go 소스 코드 → go build → 네이티브 바이너리
                              ↓
                    import "net/http"     ← Go 표준 라이브러리
                    import "github.com/..." ← Go 생태계 전체
                    import "harbour-go/hbrt" ← Harbour 런타임

결과: Harbour 문법으로 작성하되
     Go의 모든 것을 사용할 수 있는 새로운 언어

핵심 원칙

원칙 1: Harbour 문법 호환
  기존 PRG 코드가 최소 수정으로 컴파일되어야 한다.
  100% 호환이 아니라 95% 호환 + 마이그레이션 도구.

원칙 2: Go 생태계 1급 시민
  Go 패키지를 PRG에서 직접 import하여 사용할 수 있어야 한다.
  PRG 함수를 Go에서 직접 호출할 수 있어야 한다.

원칙 3: Go 철학 수용
  "공유 메모리로 통신하지 말고, 통신으로 메모리를 공유하라"
  에러는 값이다 (panic이 아닌 error 반환)
  단순함을 추구한다

원칙 4: 전진적 진화
  Clipper 호환 quirk는 선택적 호환 모드로 분리한다.
  새 코드는 현대적 패턴을 권장한다.
  기존 코드는 점진적으로 마이그레이션한다.

4. Go 생태계 직접 연동

4.1 PRG에서 Go 패키지 사용

현재 (불가능):

// Harbour에서 HTTP 서버? → 없음
// JSON 파싱? → 제한적
// PostgreSQL? → contrib/hbpgsql (불안정)

Five에서 (직접 사용):

// Five 문법 확장: IMPORT
IMPORT "net/http"
IMPORT "encoding/json"
IMPORT "database/sql"
IMPORT _ "github.com/lib/pq"   // PostgreSQL 드라이버

FUNCTION StartServer(cPort)
   LOCAL oMux := http.NewServeMux()

   oMux:HandleFunc("/api/customers", {|w, r|
      LOCAL aData := GetCustomers()
      LOCAL cJson := json.Marshal(aData)
      w:Write(cJson)
   })

   ? "Server starting on port " + cPort
   http.ListenAndServe(":" + cPort, oMux)
   RETURN NIL

생성되는 Go 코드:

package main

import (
    "net/http"
    "encoding/json"
    "database/sql"
    _ "github.com/lib/pq"
    "harbour-go/hbrt"
)

func HB_STARTSERVER(t *hbrt.Thread) {
    t.Frame(1, 2)
    defer t.EndProc()

    mux := http.NewServeMux()
    t.PushGoValue(mux)
    t.PopLocal(2)  // oMux

    // HandleFunc with Harbour code block
    mux.HandleFunc("/api/customers", func(w http.ResponseWriter, r *http.Request) {
        bt := t.VM().NewThread()
        defer bt.Destroy()
        // ... Harbour 코드 블록 실행 ...
        data := bt.CallHarbour("GETCUSTOMERS")
        jsonBytes, _ := json.Marshal(hbrt.ToGoValue(data))
        w.Write(jsonBytes)
    })

    http.ListenAndServe(":" + t.LocalAsString(1), mux)
}

4.2 Go에서 Five/Harbour 호출

// Go 프로젝트에서 Five를 라이브러리로 사용
package main

import (
    "fmt"
    "harbour-go/hbrt"
    _ "myapp/harbour_modules"  // PRG에서 생성된 Go 코드
)

func main() {
    vm := hbrt.NewVM()

    // Harbour 함수 호출
    result := vm.Call("CalcTax", 50000.0, "KR")
    fmt.Printf("Tax: %.2f\n", result.AsDouble())

    // Harbour의 RDD를 Go에서 사용
    vm.Exec(`
        USE customers VIA DBFCDX
        SET FILTER TO country = "KR"
        GO TOP
    `)

    // 결과를 Go 구조체로 변환
    for !vm.Call("EOF").AsBool() {
        name := vm.Call("FIELD->NAME").AsString()
        fmt.Println(name)
        vm.Exec("SKIP")
    }
}

4.3 타입 브릿지

Five Value ←→ Go 타입 자동 변환

Five                    Go
───────                ──────
NIL                    nil (interface{})
LOGICAL (.T./.F.)      bool
INTEGER/LONG           int64
DOUBLE                 float64
STRING                 string
DATE                   time.Time
TIMESTAMP              time.Time
ARRAY                  []interface{} 또는 []hbrt.Value
HASH                   map[string]interface{} 또는 map[hbrt.Value]hbrt.Value
OBJECT                 *hbrt.Object (Go interface 구현 가능)
BLOCK                  func(...hbrt.Value) hbrt.Value
// 타입 브릿지 API
hbrt.ToGoValue(v Value) interface{}      // Five → Go
hbrt.FromGoValue(v interface{}) Value    // Go → Five

// 구조체 매핑
type Customer struct {
    Name    string  `hb:"cName"`
    Age     int     `hb:"nAge"`
    Active  bool    `hb:"lActive"`
}

// Five 객체 → Go 구조체
var cust Customer
hbrt.Unmarshal(hbObject, &cust)

// Go 구조체 → Five 해시
hbHash := hbrt.Marshal(cust)

5. 동시성 모델 진화

5.1 현재: Harbour의 깨진 스레딩

// 현재 Harbour: 불안정, 실무에서 회피
hb_threadStart(@Worker())

STATIC FUNCTION Worker()
   // 글로벌 상태 접근 → 레이스 컨디션
   // GC 타이밍 → 크래시
   // 에러 처리 → 불완전
   RETURN NIL

5.2 Five: goroutine 네이티브 통합

새 키워드: GO (goroutine 시작)

FUNCTION ProcessOrders(aOrders)
   LOCAL ch := CHANNEL(10)    // 버퍼 채널

   // goroutine으로 병렬 처리
   FOR EACH oOrder IN aOrders
      GO ProcessOne(oOrder, ch)
   NEXT

   // 결과 수집
   LOCAL aResults := {}
   FOR i := 1 TO Len(aOrders)
      AAdd(aResults, RECEIVE(ch))
   NEXT

   RETURN aResults

FUNCTION ProcessOne(oOrder, ch)
   LOCAL nTotal := CalcTotal(oOrder)
   SEND(ch, {oOrder:id, nTotal})
   RETURN NIL

생성되는 Go 코드:

func HB_PROCESSORDERS(t *hbrt.Thread) {
    t.Frame(1, 2)
    defer t.EndProc()

    ch := make(chan hbrt.Value, 10)
    t.PushGoValue(ch)
    t.PopLocal(2)

    orders := t.Local(1).AsArray()
    for _, order := range orders.Items() {
        order := order  // capture
        go func() {
            gt := t.VM().NewThread()
            defer gt.Destroy()
            gt.PushSymbol(sym_PROCESSONE)
            gt.PushNil()
            gt.PushValue(order)
            gt.PushGoValue(ch)
            gt.Function(2)
        }()
    }

    results := hbrt.NewArray(0)
    for i := 0; i < orders.Len(); i++ {
        val := <-ch
        results.Add(val)
    }
    t.PushValue(hbrt.MakeArrayFrom(results))
    t.RetValue()
}

5.3 동시성 프리미티브

// 채널 (Go channel)
LOCAL ch := CHANNEL(0)       // unbuffered
LOCAL ch := CHANNEL(100)     // buffered

SEND(ch, value)              // ch <- value
LOCAL val := RECEIVE(ch)     // val := <-ch

// SELECT (Go select)
SELECT CHANNEL
   CASE val := RECEIVE(ch1)
      ? "From ch1:", val
   CASE val := RECEIVE(ch2)
      ? "From ch2:", val
   CASE AFTER(5000)          // 5초 타임아웃
      ? "Timeout"
END SELECT

// WaitGroup
LOCAL wg := WAITGROUP()
FOR i := 1 TO 10
   wg:Add(1)
   GO func(wg, i)
NEXT
wg:Wait()

// Mutex (필요한 경우만)
LOCAL mtx := MUTEX()
mtx:Lock()
// critical section
mtx:Unlock()

5.4 안전한 공유: 구조적 보장

// Five는 구조적으로 레이스를 방지한다:

// 규칙 1: LOCAL 변수는 goroutine-local → 공유 불가능
// 규칙 2: 데이터 공유는 CHANNEL로만
// 규칙 3: PUBLIC 변수는 atomic read/write
// 규칙 4: STATIC 변수 접근은 자동 sync

// 컴파일러가 감지하고 경고:
STATIC nCount := 0
GO {||
   nCount++    // WARNING: STATIC access in goroutine.
               // Use CHANNEL or ATOMIC() instead.
}

6. 네트워크 네이티브

6.1 HTTP 서버 (내장)

IMPORT "harbour-go/hbweb"

FUNCTION Main()
   LOCAL oApp := hbweb.New()

   // REST API 라우팅
   oApp:GET("/api/customers", @ListCustomers())
   oApp:GET("/api/customers/:id", @GetCustomer())
   oApp:POST("/api/customers", @CreateCustomer())
   oApp:PUT("/api/customers/:id", @UpdateCustomer())
   oApp:DELETE("/api/customers/:id", @DeleteCustomer())

   // 미들웨어
   oApp:Use(@LogMiddleware())
   oApp:Use(@AuthMiddleware())

   oApp:Listen(":8080")
   RETURN NIL

FUNCTION ListCustomers(ctx)
   USE customers VIA DBFCDX
   LOCAL aResult := {}

   GO TOP
   DO WHILE !EOF()
      AAdd(aResult, {;
         "id"   => RecNo(), ;
         "name" => FIELD->name, ;
         "city" => FIELD->city ;
      })
      SKIP
   ENDDO
   USE

   ctx:JSON(200, aResult)
   RETURN NIL

6.2 HTTP 클라이언트

IMPORT "harbour-go/hbhttp"

FUNCTION CallExternalAPI()
   LOCAL oResp := hbhttp.Get("https://api.example.com/data", {;
      "Authorization" => "Bearer " + cToken, ;
      "Accept" => "application/json" ;
   })

   IF oResp:StatusCode == 200
      LOCAL hData := hbhttp.ParseJSON(oResp:Body)
      ? hData["result"]
   ELSE
      ? "Error:", oResp:StatusCode
   ENDIF

   RETURN NIL

6.3 WebSocket

IMPORT "harbour-go/hbws"

FUNCTION ChatServer()
   LOCAL oWS := hbws.NewServer()

   oWS:OnConnect({|conn|
      ? "Client connected:", conn:ID
   })

   oWS:OnMessage({|conn, cMsg|
      // 모든 클라이언트에 브로드캐스트
      oWS:Broadcast(cMsg)
   })

   oWS:Listen(":9090")
   RETURN NIL

6.4 gRPC

IMPORT "harbour-go/hbgrpc"

// .proto 파일에서 자동 생성된 Five 바인딩 사용
FUNCTION RunGRPCServer()
   LOCAL oServer := hbgrpc.NewServer()

   oServer:RegisterService("CustomerService", {;
      "GetCustomer"  => @GrpcGetCustomer(), ;
      "ListCustomers" => @GrpcListCustomers() ;
   })

   oServer:Listen(":50051")
   RETURN NIL

7. 멀티플랫폼 전략

7.1 Go의 크로스 컴파일 활용

# 단일 명령으로 모든 플랫폼 바이너리 생성
harbour build --target linux/amd64   myapp.prg -o myapp-linux
harbour build --target windows/amd64 myapp.prg -o myapp.exe
harbour build --target darwin/arm64  myapp.prg -o myapp-mac
harbour build --target linux/arm64   myapp.prg -o myapp-arm

# 내부적으로:
# GOOS=linux GOARCH=amd64 go build -o myapp-linux

7.2 Docker/컨테이너 최적화

# 최소 컨테이너 이미지
FROM scratch
COPY myapp /myapp
COPY data/ /data/
ENTRYPOINT ["/myapp"]

# 이미지 크기: ~10-15MB (Go 정적 바이너리)
# 기존 Harbour + C 런타임: 100MB+
// 컨테이너 친화적 설계
FUNCTION Main()
   // 환경 변수에서 설정 읽기 (12-Factor App)
   LOCAL cPort := GetEnv("PORT", "8080")
   LOCAL cDBPath := GetEnv("DB_PATH", "/data")

   // 헬스체크 엔드포인트
   oApp:GET("/health", {|ctx| ctx:JSON(200, {"status" => "ok"}) })

   // Graceful shutdown
   ON SIGNAL SIGTERM DO Shutdown()

   oApp:Listen(":" + cPort)
   RETURN NIL

7.3 임베디드/IoT

Go의 타겟:
  linux/arm     → Raspberry Pi
  linux/arm64   → ARM 서버
  linux/mips    → 라우터/IoT

Five 활용:
  → xBase 데이터 처리를 IoT 디바이스에서 직접 실행
  → 엣지 컴퓨팅: 현장에서 데이터 수집 + 필터링
  → 저사양 디바이스: Go의 낮은 메모리 사용량

8. RDD 진화: DBF를 넘어서

8.1 현재 RDD 체계 보존

// 기존 DBF 코드: 100% 호환
USE customers VIA DBFCDX
SET INDEX TO cust_name
SEEK "SMITH"
? FIELD->name, FIELD->salary
USE

8.2 새로운 RDD 드라이버: SQL 데이터베이스

// PostgreSQL을 RDD로 사용
USE "customers" VIA PGSQL CONNECTION "postgres://localhost/mydb"

// 동일한 xBase 명령어로 조작!
GO TOP
SET FILTER TO salary > 50000
DO WHILE !EOF()
   ? FIELD->name, FIELD->salary
   REPLACE salary WITH salary * 1.1
   SKIP
ENDDO
USE

// 내부적으로:
// GO TOP       → SELECT * FROM customers
// SET FILTER   → WHERE salary > 50000
// FIELD->name  → row["name"]
// REPLACE      → UPDATE customers SET salary = ... WHERE id = ...
// SKIP         → cursor.Next()

8.3 RDD 드라이버 맵

기존 (보존):
  DBFNTX    → DBF + NTX 인덱스
  DBFCDX    → DBF + CDX 인덱스
  DBFFPT    → DBF + 메모 필드

새로 추가:
  PGSQL     → PostgreSQL (database/sql + lib/pq)
  MYSQL     → MySQL (database/sql + go-sql-driver/mysql)
  SQLITE    → SQLite (database/sql + mattn/go-sqlite3)
  MONGODB   → MongoDB (go.mongodb.org/mongo-driver)
  REST      → REST API 엔드포인트를 테이블처럼 사용
  CSV       → CSV 파일
  JSON      → JSON 파일/API
  PARQUET   → Apache Parquet (분석용)

8.4 RDD 간 투명한 데이터 이동

// DBF에서 PostgreSQL로 마이그레이션
USE customers VIA DBFCDX
USE pg_customers VIA PGSQL CONNECTION cPgConn ALIAS pgcust

SELECT customers
GO TOP
DO WHILE !EOF()
   SELECT pgcust
   APPEND BLANK
   REPLACE name    WITH customers->name
   REPLACE salary  WITH customers->salary
   REPLACE country WITH customers->country
   SELECT customers
   SKIP
ENDDO

8.5 쿼리 언어 확장

// 기존 xBase 방식 (보존)
USE customers
SET FILTER TO country = "KR" .AND. salary > 50000
INDEX ON lastname TO temp_idx
GO TOP

// 새로운 방식: 인라인 쿼리
LOCAL aResult := QUERY FROM customers ;
                 WHERE country = "KR" .AND. salary > 50000 ;
                 ORDER BY lastname ;
                 INTO ARRAY

// SQL 직접 실행 (SQL RDD 사용 시)
LOCAL aRows := SQL("SELECT name, salary FROM customers WHERE country = $1", "KR")

9. 언어 진화 제안

9.1 에러 처리 현대화

현재: BEGIN SEQUENCE (goto 기반)

BEGIN SEQUENCE
   USE customers
   // ...
RECOVER USING oErr
   ? "Error:", oErr:description
END SEQUENCE

추가: TRY-CATCH (Go error 스타일 옵션)

// 방식 A: 기존 방식 (호환)
BEGIN SEQUENCE
   result := RiskyOperation()
RECOVER USING oErr
   LogError(oErr)
END SEQUENCE

// 방식 B: 새 방식 (Go 스타일, 선택적)
result, err := RiskyOperation()
IF err != NIL
   LogError(err)
   RETURN NIL
ENDIF

9.2 타입 힌트 (선택적)

// 기존: 타입 없음 (호환)
FUNCTION Add(a, b)
   RETURN a + b

// 새로운: 타입 힌트 (선택적, 컴파일러 최적화에 활용)
FUNCTION Add(a AS NUMERIC, b AS NUMERIC) AS NUMERIC
   RETURN a + b

// 구조체 타입 (Go struct와 브릿지)
TYPE Customer
   DATA cName AS STRING
   DATA nAge  AS INTEGER
   DATA lActive AS LOGICAL := .T.
END TYPE

// 컴파일러가 타입 힌트를 활용하여:
// 1. 더 효율적인 Go 코드 생성
// 2. 컴파일 타임 타입 체크
// 3. Go 구조체와 직접 매핑

9.3 람다 / 화살표 함수

// 기존: 코드 블록 (호환)
ASort(arr, {|a,b| a < b})
AEval(arr, {|x| QOut(x)})

// 새로운: 화살표 함수 (여러 줄 가능)
ASort(arr, (a, b) => a < b)

transformed := AMap(arr, (x) => {
   LOCAL result := ProcessItem(x)
   RETURN result * 2
})

9.4 패턴 매칭 (새 기능)

// 타입 기반 분기
SWITCH TYPE OF value
   CASE NUMERIC
      ? "Number:", value
   CASE STRING
      ? "Text:", value
   CASE ARRAY
      ? "Array with", Len(value), "items"
   CASE OBJECT
      ? "Object of class:", value:ClassName()
   OTHERWISE
      ? "Unknown type"
END SWITCH

9.5 구조적 분해 (새 기능)

// 배열 분해
LOCAL {a, b, c} := {1, 2, 3}

// 해시 분해
LOCAL {name, age} := {"name" => "Kim", "age" => 30}

// 함수 다중 반환 (Go 스타일)
FUNCTION Divide(a, b)
   IF b == 0
      RETURN 0, .T.    // result, error
   ENDIF
   RETURN a / b, .F.

LOCAL result, lError := Divide(10, 3)

9.6 호환성 모드 플래그

// 파일 또는 프로젝트 레벨에서 호환 모드 지정
#pragma compatibility(clipper)    // Clipper 호환 quirks 활성화
#pragma compatibility(harbour)    // Harbour 호환
#pragma compatibility(five)       // Five 모던 모드 (기본값)

// clipper 모드:
//   - STRING - STRING: 패딩 동작
//   - DATE + DATE: 줄리안 합산
//   - SET EXACT OFF 기본
//   - 63자 심볼 이름 제한

// five 모드:
//   - STRING - STRING: 에러 (의미 없는 연산)
//   - DATE + DATE: 에러
//   - SET EXACT ON 기본
//   - 심볼 이름 제한 없음
//   - 타입 힌트 활성화
//   - 다중 반환 활성화

10. 기존 코드 마이그레이션

10.1 마이그레이션 도구

# 기존 PRG 코드 분석
harbour migrate analyze ./src/*.prg

# 출력:
# ─────────────────────────────────────
# 파일 분석 완료: 150개 PRG 파일
#
# 호환성:
#   즉시 컴파일 가능:  120 (80%)
#   자동 수정 가능:     25 (17%)
#   수동 수정 필요:      5 (3%)
#
# 자동 수정 항목:
#   IIF → iif (대소문자)              : 45건
#   SET PRINTER → 제거 (콘솔 출력 변경) : 12건
#   ANNOUNCE → 불필요 (Go 모듈로 대체)  : 8건
#
# 수동 수정 항목:
#   인라인 C 코드 (#pragma BEGINDUMP) : 3건
#   OS별 API 호출 (WinAPI)           : 2건
# ─────────────────────────────────────

# 자동 수정 적용
harbour migrate fix ./src/*.prg --output ./src_five/

10.2 점진적 마이그레이션 패턴

Phase A: 기존 PRG을 Five로 컴파일 (최소 변경)
  → 95% 코드가 그대로 동작
  → 나머지 5%는 마이그레이션 도구가 변환

Phase B: 새로운 기능은 Five 확장 문법으로 작성
  → Go 패키지 import
  → goroutine 사용
  → HTTP API 추가

Phase C: 기존 코드를 점진적으로 현대화
  → 타입 힌트 추가
  → 에러 처리 현대화
  → SQL RDD로 DB 마이그레이션

10.3 C 코드 (#pragma BEGINDUMP) 처리

// 기존: C 인라인 코드
#pragma BEGINDUMP
#include <hbapi.h>
HB_FUNC( MYEXTFUNC )
{
   hb_retni( some_c_library_call() );
}
#pragma ENDDUMP

마이그레이션 옵션:

옵션 A: CGo로 변환
  → C 코드를 CGo wrapper로 감쌈
  → 기존 C 라이브러리 계속 사용 가능
  → 성능 오버헤드 있음 (CGo 호출 비용)

옵션 B: Go 네이티브로 재작성
  → C 라이브러리의 Go 대안 사용
  → 가장 깔끔하지만 작업량 큼

옵션 C: Five 플러그인 시스템
  → Go plugin 또는 Wasm으로 확장
  → 독립적인 빌드/배포

11. 생태계 구축 전략

11.1 패키지 매니저

# Go modules 기반
harbour mod init myapp
harbour mod tidy

# go.mod 파일이 의존성 관리
# harbour.mod 파일이 Five 특화 설정 관리
harbour.mod:
  module myapp
  five 1.0
  compatibility harbour

  require (
      harbour-go/hbrt v1.0.0
      harbour-go/hbrtl v1.0.0
      harbour-go/hbrdd v1.0.0
      harbour-go/hbweb v1.0.0
  )

go.mod:
  module myapp
  go 1.23

  require (
      harbour-go/hbrt v1.0.0
      github.com/lib/pq v1.10.0
      // ... Go 의존성
  )

11.2 표준 라이브러리 확장

harbour-go/hbrt      ← 핵심 런타임 (Value, Thread, Symbol, Class)
harbour-go/hbrtl     ← 기존 RTL 호환 함수 (STR, VAL, SUBSTR, ...)
harbour-go/hbrdd     ← RDD 프레임워크 + DBF/NTX/CDX 드라이버
harbour-go/hbweb     ← HTTP 서버/클라이언트 프레임워크
harbour-go/hbsql     ← SQL RDD 드라이버 (PG, MySQL, SQLite)
harbour-go/hbjson    ← JSON/XML/YAML 처리
harbour-go/hbcli     ← CLI 프레임워크 (cobra 기반)
harbour-go/hbtest    ← 테스트 프레임워크
harbour-go/hblog     ← 구조적 로깅 (slog 기반)
harbour-go/hbcrypto  ← 암호화/해싱
harbour-go/hbmail    ← 이메일 발송

11.3 개발 도구

harbour lsp          ← Language Server Protocol (에디터 통합)
harbour dap          ← Debug Adapter Protocol (디버거)
harbour fmt          ← 코드 포매터
harbour lint         ← 린터 (코드 품질 검사)
harbour test         ← 테스트 러너
harbour doc          ← 문서 생성기
harbour repl         ← 대화형 셸
harbour migrate      ← 마이그레이션 도구

11.4 VSCode 확장

five-vscode/
├── syntaxes/         ← TextMate 문법 (구문 강조)
├── language-configuration.json
├── snippets/         ← 코드 스니펫
└── extension.js      ← LSP 클라이언트 연결

12. 아키텍처 총괄

전체 시스템 구조

┌──────────────────────────────────────────────────────────┐
│                    Five CLI                                │
│  harbour build | run | fmt | lint | test | lsp | migrate  │
└──────────┬───────────────────────────────────┬───────────┘
           │                                   │
    ┌──────▼──────┐                    ┌───────▼───────┐
    │  Compiler    │                    │  Dev Tools    │
    │  ┌────────┐  │                    │  LSP, DAP,    │
    │  │ Lexer  │  │                    │  Formatter    │
    │  ├────────┤  │                    └───────────────┘
    │  │ Parser │  │
    │  ├────────┤  │
    │  │Analyzer│  │
    │  ├────────┤  │
    │  │ GenGo  │  │ ← PRG → Go 소스 생성
    │  └────────┘  │
    └──────┬───────┘
           │ 생성된 .go 파일
           ▼
    ┌──────────────────────────────────────────────────────┐
    │                  Go Build System                      │
    │  go build (표준 Go 컴파일러)                          │
    │                                                       │
    │  의존성:                                              │
    │  ┌────────────────────────────────────────────────┐  │
    │  │  harbour-go/hbrt    ← 핵심 런타임              │  │
    │  │  harbour-go/hbrtl   ← 표준 함수 라이브러리     │  │
    │  │  harbour-go/hbrdd   ← 데이터베이스 드라이버    │  │
    │  │  harbour-go/hbweb   ← 웹 프레임워크            │  │
    │  │  harbour-go/hbsql   ← SQL 드라이버             │  │
    │  ├────────────────────────────────────────────────┤  │
    │  │  net/http           ← Go 표준 라이브러리       │  │
    │  │  database/sql       ← Go 표준 라이브러리       │  │
    │  │  encoding/json      ← Go 표준 라이브러리       │  │
    │  │  github.com/...     ← Go 생태계 전체           │  │
    │  └────────────────────────────────────────────────┘  │
    └──────────────────────────┬────────────────────────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │  단일 네이티브 바이너리 │
                    │  (정적 링크, ~10MB)    │
                    │  모든 OS/아키텍처      │
                    └─────────────────────┘

핵심 런타임 내부 구조

hbrt (harbour-go runtime)
├── Value          ← Tagged Value 16B (harbour-type-system-analysis.md 참조)
├── Thread         ← goroutine별 실행 컨텍스트
│   ├── stack      ← eval 스택 (goroutine-local, 락 불필요)
│   ├── locals     ← 로컬 변수 (goroutine-local)
│   ├── memvars    ← PRIVATE (goroutine-local map)
│   └── callStack  ← 호출 스택 (goroutine-local)
├── VM             ← 공유 상태
│   ├── symbols    ← 심볼 테이블 (sync.RWMutex)
│   ├── classes    ← 클래스 레지스트리 (sync.RWMutex)
│   ├── publics    ← PUBLIC 변수 (sync.RWMutex)
│   └── modules    ← 로드된 모듈 목록
├── ops            ← 연산 (Plus, Minus, Equal, ...)
├── Bridge         ← Go ↔ Five 타입 변환
└── Macro          ← 런타임 매크로 컴파일러

13. 로드맵

Phase 1: 기반 (Month 1-2)

목표: "Hello World"가 PRG → Go → 실행되는 것

구현:
  [x] 프로젝트 구조 설정 (Go 모듈)
  [ ] hbrt/value.go — Tagged Value 16B
  [ ] hbrt/thread.go — 스택, 로컬 변수
  [ ] hbrt/ops_arith.go — 산술 연산
  [ ] hbrt/ops_compare.go — 비교 연산
  [ ] hbrtl/console.go — QOut, QQOut
  [ ] hbrtl/strings.go — 기본 문자열 함수
  [ ] compiler/lexer.go — PRG 렉서
  [ ] compiler/parser.go — 기본 구문 파서
  [ ] compiler/gengo.go — Go 코드 생성

검증:
  FUNCTION Main()
     ? "Hello World"
     ? 1 + 2
     ? "Result: " + Str(10 * 3)
  RETURN NIL

Phase 2: 제어 흐름 + 함수 (Month 3)

목표: IF, DO WHILE, FOR, 함수 호출이 동작

추가 구현:
  [ ] 제어 흐름 (IF/ELSEIF/ELSE, DO WHILE, FOR, FOR EACH)
  [ ] 함수 정의/호출 (FUNCTION, PROCEDURE)
  [ ] LOCAL, STATIC, PRIVATE, PUBLIC 변수
  [ ] 배열/해시 연산
  [ ] 코드 블록 (기본)
  [ ] BEGIN SEQUENCE / RECOVER

검증: 기본적인 Harbour 프로그램 100개 테스트

Phase 3: RDD (Month 4-5)

목표: DBF 파일 읽기/쓰기

추가 구현:
  [ ] hbrdd/workarea.go — 워크에어리어 관리
  [ ] hbrdd/dbf.go — DBF 포맷
  [ ] hbrdd/ntx.go — NTX 인덱스
  [ ] hbrdd/cdx.go — CDX 인덱스
  [ ] USE, APPEND, REPLACE, SEEK, INDEX ON
  [ ] SET FILTER, SET RELATION

검증: 기존 DBF 데이터 파일로 CRUD 동작

Phase 4: OOP + 매크로 (Month 6)

목표: 클래스 시스템과 매크로 동작

추가 구현:
  [ ] hbrt/class.go — 클래스 정의/인스턴스
  [ ] 연산자 오버로딩
  [ ] 매크로 컴파일러 (미니 파서)
  [ ] PP (전처리기)

검증: 실제 비즈니스 애플리케이션 PRG 컴파일

Phase 5: Go 연동 (Month 7-8)

목표: Go 패키지를 PRG에서 사용

추가 구현:
  [ ] IMPORT 문법
  [ ] Go ↔ Five 타입 브릿지
  [ ] hbweb — HTTP 서버/클라이언트
  [ ] hbsql — SQL RDD (PostgreSQL, SQLite)
  [ ] 동시성 프리미티브 (GO, CHANNEL, SEND, RECEIVE)

검증: REST API 서버를 PRG로 작성하여 배포

Phase 6: 도구 + 생태계 (Month 9-10)

목표: 개발 경험 완성

추가 구현:
  [ ] harbour fmt — 코드 포매터
  [ ] harbour lsp — Language Server
  [ ] harbour test — 테스트 프레임워크
  [ ] harbour migrate — 마이그레이션 도구
  [ ] VSCode 확장
  [ ] 문서 사이트

검증: 실제 프로젝트에서 개발 → 빌드 → 배포 완전 사이클

Phase 7: 언어 진화 (Month 11-12)

목표: Five 고유 기능 추가

추가 구현:
  [ ] 타입 힌트 (선택적)
  [ ] 다중 반환
  [ ] 구조적 분해
  [ ] 패턴 매칭
  [ ] 호환성 모드 플래그
  [ ] 추가 RDD 드라이버 (MongoDB, REST, Parquet)

검증: Five 쇼케이스 프로젝트 공개

변경 이력

날짜 변경 내용
2026-03-27 초기 작성. Harbour+Go 융합 전략, 언어 진화, 생태계 설계