본문으로 건너뛰기

헤더 행과 컬럼 경로

「주 시트 레이아웃」으로 돌아가기


4. :type 행 — 접힌 타입 표현과 괄호 메타

4.1 타입 표현 — 디테일 행의 소멸

기존 레이아웃은 (타입 칸, 디테일 칸) 한 쌍이었습니다 — 타입 enum + 디테일 Element, 타입 foreign + 디테일 Weapon|Armour. STRUCT DSL이 그 쌍을 타입 표현 하나로 접었고 (설계 §3), 이 레이아웃은 그 접힌 표현을 시트에서도 씁니다. 디테일 행은 없습니다.

무엇기존 (타입 + 디테일)이 레이아웃
enumenum + ElementElement
참조foreign + Weapon|Armourforeign Weapon|Armour
DSL의 struct(없었음)Reward
그 외int · string[] · vec3f · …그대로

대안 — 타입과 디테일을 행 둘로 유지. 행 키 레이아웃 §3.3이 엑셀 드롭다운 검증을 위해 택하였던 방향입니다. 채택하지 않습니다 — DSL과 시트가 같은 타입 표현을 쓰는 것이 배우는 문법을 하나로 만들고, 자리 둘에 뜻 하나를 나눠 적는 형태가 §11에서 피하려는 것 자체이기 때문입니다. 드롭다운은 이름 카탈로그 산출로 보완하는 방향이고 미결로 남깁니다(§13).

4.2 괄호 메타 — 첫 (부터는 언제나 메타

타입 칸은 「타입 표현 + 괄호 메타(선택)」입니다. 규칙은 하나입니다 — 셀에서 첫 (가 나오면 거기서부터 메타입니다. 타입 표현 자체에는 괄호가 없습니다.

int
int? (min=0, max=100)
string (text)
string (text=Common)
string (asset=icon)
foreign Item|CharGear
Reward
int[] (size=1..4)
메타 키대응
text플래그 또는 그룹 이름번역 수집. (text) · (text=Common)기존 text · text(Common) 타입
namespace이름text 그룹의 네임스페이스기존 text(Common,Shared)의 둘째 자리
asset종류 이름자산 존재 확인. (asset=icon)기존 asset(icon) 타입
min · max범위. 스칼라 · 원소Field.ConstraintsMinimum · Maximum
alloweda;b;c허용값AllowedValues
regex · size · notDefault(DSL §6.1과 동일)컬럼 제약Luban 대조 §5.8의 도입 항목
  • 키의 사전과 「배열에 붙는가, 원소에 붙는가」는 DSL §6.1의 표가 정본입니다. 이 레이아웃이 키를 따로 정의하지 않습니다 — 같은 키, 같은 뜻, 같은 검증입니다. text · namespace · asset의 등재는 괄호 메타와 같은 단계입니다(§16의 3).
  • DSL이 선언한 struct의 컬럼에 적은 제약은 DSL 제약과의 교집합입니다(DSL §6.3). 완화는 없습니다.
  • 모르는 키는 오류입니다.

role 키 등재에서 확인해 둔 것 3가지(§16의 3의 입력입니다).

  • DSL은 text를 플래그로만 읽습니다SchemaMetadata.ApplyRoleHas("text")만 보므로 (text=Common)은 파싱을 통과하고 Common이 조용히 버려집니다. 등재가 고치는 결함이고, 이 도구가 없애려는 종류 그 자체입니다.
  • DSL에 namespace 키가 없습니다. 시트의 옛 표기는 text(Common,Shared)의 둘째 자리로 적었고, key=value 형태에는 쉼표 묶음이 필요 없으므로 키를 따로 둡니다 — 양쪽이 같은 형태가 되는 것이 등재의 본 효과입니다.
  • 기존 role 오류 문구는 옛 표기 전용입니다 — 「괄호를 열고」 · 「쉼표로 끝나고」 · text(Achievement,Quests)를 안내합니다. key=value에 그대로 쓰면 작성자가 쓰지 않은 표기를 안내하게 되므로, 규칙은 공유하고 문구는 표기마다 따로 둡니다CookingContext.RequiresRoleGroup의 판정을 뽑아 쓰고 메시지는 각자입니다.

기존 표기와의 단절 하나. text(Common) · asset(icon)처럼 괄호가 타입에 붙는 표기는 이 레이아웃에 없습니다 — 붙여 적으면 (Common)이 메타로 읽혀 「모르는 키」로 걸리므로, 그 오류 메시지가 (text=Common) 형태를 안내해야 합니다. 기존 tabbit 레이아웃의 시트는 교체(§16의 6) 전까지 기존 파서로 유효하고, 이관에서 이 표기도 함께 고칩니다.

4.3 타입 칸을 적는 자리 — 그룹의 정본은 첫 멤버 컬럼

컬럼의 형태타입 칸
스칼라 컬럼그 컬럼에 적습니다
인라인(익명) 레코드 그룹 — pos.x · pos.y멤버 컬럼마다 적습니다
DSL struct 그룹 — (나)그룹의 첫 멤버 컬럼에 struct 이름 하나. 나머지 멤버 칸은 비웁니다 — 적으면 DSL과의 일치를 검사하고 어긋나면 거부합니다(DSL §7.2)
원소 번호 그룹 — slots[0].id · slots[1].id원소 0의 컬럼에만 적습니다. 이후 원소의 타입 칸은 비웁니다 — 적으면 일치 검사
멀티 로우 그룹 — rewards[].itemId위 두 규칙과 같습니다. 타입 칸에 적는 것은 원소의 타입입니다 — 배열임은 이름의 []에 이미 적혀 있으므로 타입에 다시 적지 않습니다

:desc · :target · 제약 메타도 같은 규칙입니다 — 그룹의 정본은 첫 멤버 컬럼(원소 0)이고, 반복 기재는 일치 검사입니다.


5. :field 행 — 컬럼 경로 표기

경로의 정본은 대괄호 원소 번호와 점 멤버입니다. 다른 레이아웃의 character[0]["Id"](NamedRangeColumnPath)와 기존 tabbit의 Slot1.Id가 이 표기 하나로 합류합니다.

:field
id필드 하나
pos.x레코드 pos의 멤버 x
slots[0].id레코드 배열 slots의 원소 0, 멤버 id칸의 수가 정해진 배열
tags[0] · tags[1]스칼라 배열을 컬럼으로
pos.x[0]멤버가 배열인 레코드 (다중 중첩Pos.X1)
grid[0][1]배열의 배열 — 대괄호가 이어지면 안쪽 레벨은 이름이 없습니다
rewards[].itemId멀티 로우 — 원소가 컬럼이 아니라 에서 옵니다(§6)
costs[]스칼라 멀티 로우
Price@3 · *code · #old@4와이어 태그 · 보조 인덱스 · Tombstone — 기존 그대로
  • 원소 번호는 0부터이고 빠짐없이 연속해야 합니다. [1]부터 시작하거나 건너뛰면 그 셀을 가리켜 오류입니다.
  • 이름의 숫자 접기(Slot1 · Slot2 → 배열)는 이 레이아웃에 없습니다. FoldSerialFields 옵션은 없어졌습니다 — 그 옵션이 있던 이유가 옛 표기에 「이 숫자가 배열이다」를 말할 자리가 없었다는 것뿐이고, 대괄호가 그것을 말하므로 존재 이유가 함께 사라집니다(§16.7). Text1 · Text2는 그냥 필드 2개입니다. 배열은 언제나 [] 대괄호로 선언되고, 「이 이름의 숫자가 배열인가」라는 질문 자체가 없어집니다.
  • 대괄호가 이어지면 레벨이 하나 더 생기고, 그 레벨은 이름이 없습니다. grid[0][1]grid의 원소 0의 원소 1이고, 안쪽에 이름이 없는 것이 그 형태의 내용입니다 — 소비자가 적을 낱말이 없으므로 번호로 가리킵니다(다중 중첩Grid1.2가 같은 것입니다). 이름 없는 레벨은 대괄호로만 생깁니다. 점 뒤에 이름 없이 대괄호를 적는 것(grid.[1])은 오류입니다 — 한 형태를 적는 방법이 둘이 되지 않게 하기 위해서입니다.
  • 중첩 깊이는 세지 않습니다 — stars[0].pos.xslots[0].id와 같은 규칙 한 단계 더입니다(다중 중첩).
  • 와이어 태그는 와이어 컬럼당 하나입니다. slots[0].id@4처럼 원소 0의 멤버 컬럼에 달고, 이후 원소 컬럼에는 달지 않습니다(기존 serial field 규칙과 동형). 멀티 로우 그룹은 멤버 컬럼이 곧 와이어 컬럼이므로 rewards[].itemId@4처럼 멤버마다 답니다.
  • * 보조 인덱스는 [] · [n] 컬럼에 붙을 수 없습니다(배열은 인덱스가 될 수 없다는 기존 규칙).

5.1 []의 두 자리 — 이름과 타입

[]가 이름에 있으면 행이 원소이고, 타입에 있으면 셀 안이 원소입니다.

기재원소가 오는 곳길이
:field costs + :type int[]셀 안10;20;30셀마다 다름
:field costs[] + :type int — 연장 행마다 하나행 수가 정함
:field costs[0] costs[1] + :type int컬럼 — 칸의 수가 정해짐컬럼 수. TrimTrailingArrayElements로 뒤를 자를 수 있음

셋 다 와이어는 같습니다 — KindVarArray 컬럼 하나(가변 길이 레코드 배열)이고, 생성 코드도 같습니다. 다른 것은 시트에서 읽는 방법뿐입니다.

costs[] + int[]처럼 두 자리에 동시에 적는 것(행마다 셀 배열 — 배열의 배열)은 1차에서 거부합니다(§13).


6. 멀티 로우 — 정밀 규칙

레코드 하나가 여러 행에 걸치는 표기입니다. Luban의 * 멀티 로우가 원형이고, 경계 판정을 바꿨습니다(아래 근거).

6.1 규칙

#규칙
1:field[] 컬럼이 하나라도 있으면 그 테이블은 멀티 로우 모드입니다. 없으면 지금처럼 한 행이 한 레코드입니다
2새 레코드의 시작은 기본 인덱스 칸에 값이 있는 행입니다(§3.5의 첫 키 — 복합이면 성분 중 하나라도). 그 칸이 전부 빈 행은 직전 레코드의 연장 행이고, 복합 키의 성분 일부만 채운 행은 그 빈 성분을 가리켜 오류입니다
3연장 행에서 값이 허용되는 곳은 [] 컬럼뿐입니다. 그 외 컬럼(스칼라 · [n] · 메타가 아닌 것)에 값이 있으면 그 셀을 가리켜 오류입니다
4원소의 성립 — 레코드에 속한 각 행(첫 행 포함)에서, 한 [] 그룹의 컬럼 범위에 값이 하나라도 있으면 그 행이 그 그룹의 원소 하나입니다. 전부 비어 있으면 그 행에는 그 그룹의 원소가 없습니다
5[] 그룹이 여럿이면 각자 독립적으로 쌓입니다. 길이가 서로 다를 수 있고, 같은 행에 있다고 원소끼리 짝이 되는 것이 아닙니다
6원소 안의 빈 칸은 일반 규칙입니다 — 빈 칸과 없음OnBlankCell 정책 그대로
7완전히 빈 행은 엔티티의 종료입니다(§3.2). 레코드 사이에 빈 행을 둘 수 없습니다 — 여백이 필요하면 마커 열 #
8마커 열의 #레코드의 첫 행에 있으면 연장 행까지 레코드 전체를 제외하고, 연장 행에 있으면 그 행의 원소들만 제외합니다
9키 컬럼(§3.5)은 []일 수 없습니다 — 배열은 인덱스가 될 수 없다는 기존 규칙 그대로입니다

6.2 경계 판정의 근거 — Luban과 다른 곳

Luban의 연장 판정은 「멀티 로우가 아닌 모든 컬럼이 빈 행」입니다. 그 규칙에서는 연장 행에 스칼라 값을 실수로 적으면 그 행이 새 레코드가 되고, 오류는 「키가 비었다」로 납니다 — 사용자가 한 실수(잘못된 자리에 값)와 메시지(키 누락)가 서로 다른 곳을 가리킵니다.

이 설계는 신호를 인덱스 칸 하나로 좁혔습니다. 인덱스가 비면 연장이고, 연장 행의 스칼라 값은 규칙 3이 「이 값은 첫 행에 있어야 합니다」라고 그 셀을 가리킵니다. 반대 실수 — 연장하려던 행의 인덱스에 값을 적음 — 는 새 레코드가 되지만, 그 행의 스칼라 칸들이 비어 있으므로 기본 정책(OnBlankCell: Error)이 검출합니다. 어느 방향의 실수든 조용히 지나가지 않습니다.

6.3 담지 않는 것

무엇판정
중첩 멀티 로우[] 그룹의 멤버가 또 []1차 거부. Luban은 임의 깊이를 지원하지만, 안쪽 배열은 셀 배열이나 [n] 칸으로 충분히 적습니다. 요구가 실측되면 그때 형태를 정합니다
[] 그룹의 옵셔널 — []?1차 거부. 원소 0개(빈 배열)로 충분하고, 「배열이 없음」이 필요한 컬럼은 셀 배열 T[]?로 적습니다
행마다 셀 배열 — costs[] + int[]1차 거부(§5.1)

6.4 와이어 — 형식 무변경

멀티 로우 그룹의 멤버는 KindVarArray 컬럼 하나입니다 — 가변 길이 레코드 배열이 이미 실어 둔 형태이고, 이 레이아웃은 그 배열에 원소를 공급하는 세 번째 방법(행)일 뿐입니다. 형식도 생성 코드도 움직이지 않습니다. TrimTrailingArrayElements · AllowArrayGaps[n] 고정 칸의 질문이므로 멀티 로우에는 해당하지 않습니다 — 원소는 있는 행만큼 생기고, 사이가 빈 원소는 규칙 4가 「원소 없음」으로 읽습니다.


7. 예약 컬럼 — $type · $key · $value

:field 행에서 $로 시작하는 이름은 예약 컬럼입니다. Luban의 $type · $key · $value와 같은 이름이고, 이번 구현에서는 셋 다 이름을 인식하고 「아직 지원하지 않는다」로 거부합니다 — 자리를 지금 확보해 두면 뒤의 스펙이 문법을 다시 정하지 않습니다.

경로의 마지막 마디에서 판정합니다effect.$typeeffect 그룹의 판별자입니다. 그 자리 말고는 어디서도 $가 이름에 들어가지 않으므로, 식별자 검사의 예외도 그 한 자리입니다.

예약 컬럼장래의 역할선행 스펙
$type다형 레코드의 변종 판별 — 행(원소)마다 변종 이름을 적는 컬럼다형과 참조 배열이 그 설계입니다 — 와이어는 형식 무변경이고(§6), 이 컬럼의 표기는 그 문서 §5.2입니다
$keymap의 키 컬럼 — prices[] 그룹에서 키가 들어가는 자리DSL 5′ (set · map). 셀 표기(1:sword;2:shield)와 컬럼 표기의 확정이 거기입니다
$value다형 변종의 값을 한 셀로 압축(Luban $value)거부 유지다형과 참조 배열 §10이 그 판정을 그대로 두었습니다. (다) sep 표기와 겹치는 두 번째 방법이 됩니다

Luban에서 확인해 둔 것 중 이 자리의 설계에 물려받을 판정 2가지입니다.

  • 다형 변종 컬럼의 열 집합은 모든 변종의 합집합이고, 그 행의 변종에 없는 컬럼은 비웁니다 — 멀티 로우와 결합하면 원소가 되는 행마다 $type 셀이 변종을 정합니다.
  • 옵셔널이지만 다형이 아닌 레코드에까지 판별 컬럼을 강제하는 것(Luban의 null · {} 규칙)은 따라가지 않습니다. tabbit의 레코드 멤버 옵셔널은 별도 설계가 이미 있습니다.

7.1 여러 테이블 중 하나와 다형 — 섞이면 안 되는 두 가지

겉모습이 비슷해서 혼동하기 쉽지만 다른 층의 다른 질문입니다. 이 구분이 흐려지면 같은 요구가 두 문법으로 적히게 되므로, 표로 박아 둡니다.

여러 테이블 중 하나 refs=A;B다형 레코드 (:type)
질문키 값이 어느 테이블의 행인가레코드 자체가 어떤 형태인가
컬럼이 담는 것키 하나. 컬럼의 형태는 행마다 같습니다행마다 다른 멤버 집합
답이 정해지는 곳값을 대상들의 인덱스에서 찾아서:type 셀에 적힌 이름으로
tabbit의 현재검사만 있습니다. 참조로 올리는 것은 되돌렸습니다 — 셀렉터에는 돌려줄 타입이 없습니다 (설계)설계까지다형과 참조 배열. 구현은 없습니다
Luban의 대응물ref=의 다중 테이블(검사만)$type

「보상이 아이템일 수도 장비일 수도 있다」는 참조의 문제이지만 행에 닿는 참조는 아닙니다int (refs=Item;CharGear)으로 적어 값이 어느 쪽의 id인지 검사하고, 행에 닿아야 하면 테이블마다 컬럼을 둡니다. 「효과 레코드의 필드 구성이 행마다 다르다」가 다형의 문제이고, 그것은 여전히 설계 단계입니다(Luban 대조 §5.2).