CRUDUI

표현식 문법

English.

이 계약은 TypeScript·PHP·Go·Rust의 조건식과 값을 반환하는 삼항식을 정의합니다. 디자인 설정과 조건부 검증의 표현식은 같은 토큰·AST·평가 계약을 사용합니다. 동작 스크립트는 페이지의 JavaScript이며 이 엔진에서 평가하지 않습니다.

0. 처리

렉서는 소스 문자열을 토큰으로 변환합니다. 파서는 토큰을 AST로 변환합니다. 평가기는 AST, 폼 데이터, 현재 필드 경로를 받습니다. TypeScript뿐 아니라 PHP·Go·Rust도 이 단계를 구현합니다. 평가는 eval을 사용하지 않습니다.

1. 토큰

  • CUXP-001 DOT — 패턴: .; 예: .field
  • CUXP-002 DOT_DOT — 패턴: 점 두 개 이상; 예: ..field
  • CUXP-003 ASTERISK — 패턴: *; 예: items.*.name
  • CUXP-004 IDENTIFIER — 패턴: [A-Za-z_][A-Za-z0-9_]*; 예: status
  • CUXP-005 STRING — 패턴: 작은따옴표 또는 큰따옴표 문자열; 예: 'active'
  • CUXP-006 NUMBER — 패턴: 정수 또는 소수; 예: 42
  • CUXP-007 BOOLEAN — 패턴: true 또는 false; 예: true
  • CUXP-008 NULL — 패턴: null; 예: null
  • CUXP-009 EQ NE — 패턴: == !=; 예: .status == active
  • CUXP-010 GT GE LT LE — 패턴: > >= < <=; 예: .count > 0
  • CUXP-011 AND OR NOT — 패턴: && || !; 예: !.enabled
  • CUXP-012 IN NOT_IN — 패턴: in not in; 예: .country in [US, CA]
  • CUXP-013 QUESTION COLON — 패턴: ? :; 예: .enabled ? 'yes' : 'no'
  • CUXP-014 LPAREN RPAREN — 패턴: ( ); 예: (.a || .b)
  • CUXP-015 LBRACKET RBRACKET COMMA — 패턴: [ ] ,; 예: [US, CA]
  • CUXP-016 WHITESPACE — 패턴: 출력에서 제외하는 공백; 예: 공백
  • CUXP-017 EOF — 패턴: 입력 종료; 예: 입력 종료

2. 문법

파서는 비교식 하나에 비교 연산 하나를 허용합니다. 괄호는 논리식을 그룹으로 처리합니다. 삼항식 분기는 다른 삼항식을 포함할 수 있습니다.

expression = ternary ;
ternary = logic_or [ "?" ternary ":" ternary ] ;
logic_or = logic_and { "||" logic_and } ;
logic_and = negation { "&&" negation } ;
negation = "!" negation | comparison ;
comparison = primary [ ( "==" | "!=" | ">" | ">=" | "<" | "<=" ) compare_value
                       | ( "in" | "not in" ) value_list ] ;
primary = path | literal | "(" logic_or ")" ;
path = [ dots ] IDENTIFIER { "." ( IDENTIFIER | NUMBER | "*" ) } ;
dots = "." { "." } ;
compare_value = primary | IDENTIFIER ;
value_list = "[" value { "," value } "]" | value { "," value } ;
value = literal | IDENTIFIER ;
literal = STRING | NUMBER | BOOLEAN | NULL ;

비교 우변의 단독 식별자는 문자열입니다. 식별자 뒤에 점이 있거나 점으로 시작하면 경로입니다. 따라서 .status == active는 문자열과 비교하고 .a < .b는 필드 값을 비교합니다.

삼항식 분기의 문자열은 따옴표로 구분해야 합니다. 따옴표 없는 분기 식별자는 데이터 경로이므로 .vip ? gold : plain은 gold·plain 필드 값을 읽습니다.

표현식의 AST 깊이는 뿌리부터 가장 깊은 잎까지 최대 64 노드입니다. 괄호, 부정, 삼항식, 연산자는 각각 한 단계를 더합니다. ((.a))는 세 단계이고 .a || .b || .c도 왼쪽으로 중첩된 Binary 두 개이므로 세 단계입니다. 더 깊은 표현식은 Expression is nested more than 64 levels deep 메시지의 파싱 오류입니다. 파서가 한도에서 멈추므로 어떤 입력도 파서나 평가기의 스택을 소진하지 못합니다.

3. 우선순위

낮은 순서부터 높은 순서입니다.

  1. CUXP-018 ?:, 오른쪽 결합
  2. CUXP-019 ||
  3. CUXP-020 &&
  4. CUXP-021 !, 다음 비교식 또는 부정식에 적용
  5. CUXP-022 == != > >= < <= in not in, 비교 연산 하나
  6. CUXP-023 경로, 리터럴, 괄호로 구분한 논리식

예를 들어 !.a == .b는 !(.a == .b)를 의미합니다.

4. AST

노드 종류는 Ternary, Binary, Unary, In, Path, Literal, Group입니다. 경로는 식별자·와일드카드·숫자 인덱스 세그먼트를 포함합니다. 공통 고정 사례는 소스 위치를 제외한 의미 필드를 비교합니다. 토큰은 type, value, literal을 포함하며 토큰열은 공백을 제외하고 EOF로 끝납니다. 공통 고정 사례 형식은 언어별 검사에 사용하는 직렬화 필드를 정의합니다.

5. 평가

조건 평가는 불리언을 반환합니다. 값 평가는 중첩 삼항식을 포함한 삼항식에서 선택한 분기 값을 반환하고, 다른 표현식에서는 불리언 조건 결과를 반환합니다. 조건맵은 선택한 값을 저장된 그대로 반환합니다. 삼항식 외부의 단독 경로는 폼 데이터 원래 값을 반환하지 않습니다. 조건 설정의 문자열은 이 문법으로 끝까지 파싱될 때만 표현식이고 그 밖의 문자열은 리터럴 값입니다.

논리 연산자는 단축 평가합니다. 포함 검사는 ==와 같은 동등 비교를 사용하며 not in은 포함 결과를 부정합니다. 같은 스칼라 타입은 직접 비교합니다. 다른 스칼라 타입은 모두 숫자로 변환할 수 있으면 숫자로, 그렇지 않으면 문자열로 비교합니다. 스칼라와 비교할 때 배열이나 객체는 숫자가 없고 텍스트는 빈 문자열입니다. 따라서 객체에 대해 .o == '[object Object]'와 .o in '[object Object]'는 거짓이고, tags: ['a']에 대해 'a' == .tags는 거짓이며, 빈 배열에 대해 0 == .tags는 거짓이고, 어떤 배열이든 '' == .tags는 참입니다. 그 문자열 비교에서 boolean의 텍스트는 true나 false입니다. f: true에 대해 .f == 'true'는 참이고, f: false와 어떤 배열에 대해서든 .f == .tags는 거짓입니다.

두 배열이나 두 객체는 같은 JSON 값을 가질 때 같습니다. 두 배열은 길이가 같고 같은 순서로 같은 원소를 가지며, 두 객체는 key 순서와 관계없이 같은 key 집합과 각 key 아래 같은 값을 가집니다. 원소와 member 값은 변환 없이 JSON 값으로 비교합니다. 타입이 다른 값은 같지 않고, 숫자는 값으로(1은 1.0과 같음), 문자열은 문자로 비교하며, null은 null과 같습니다. 배열은 객체나 null과 같지 않습니다. wildcard 없는 경로가 가리키는 배열은 wildcard의 후보가 아니라 하나의 값입니다. .a == .b는 두 배열을 비교하고, tags: ['a']에 대해 .tags in a, b는 거짓입니다. 대소 비교는 양쪽을 숫자로 변환합니다. 문자열은 앞부분의 숫자를 사용하며 숫자가 없으면 0을 사용합니다. 이 조건 변환은 숫자 검증 규칙과 별개입니다.

상대 경로 .field는 현재 필드의 형제 필드를 해석합니다. ..field는 부모를 한 단계 더 이동하며 점이 하나 추가될 때마다 한 단계 더 이동합니다. 반복 필드의 행은 한 단계입니다. 행 키와 그 collection의 이름은 함께 떠납니다. 그룹 행의 필드에서 .field는 같은 행의 필드를, ..field는 collection 옆의 필드를 읽고, 반복 필드의 값에서 .field는 collection 옆의 필드를 읽습니다. 평가기는 현재 경로와 함께 그 행 키의 위치를 받으며, 경로를 만드는 런타임은 명세로 그 위치를 압니다. 따라서 세그먼트는 그 텍스트와 상관없이 그런 위치에 있을 때만 행 키입니다. __0000000000001__, 7, r1은 같게 해석되고, 이름이 7인 필드는 행 키가 아닙니다. 접두사가 없는 경로는 데이터 루트를 기준으로 해석합니다.

현재 경로 행 키 .x ..x
a.b 없음 a.x x
items.__k__.name __k__ items.__k__.x x
group.items.7.name 7 group.items.7.x group.x
tags.__k__ (반복 필드 tags의 값) __k__ x x: 루트에는 부모가 없습니다
누락된 값은 조건에서
거짓입니다. 필드 기본값은 폼 데이터 연결 단계에서 준비하며 표현식 평가기가
기본값을 찾기 위해 명세를 불러오지는 않습니다.

이 변환은 조건을 평가하며 필수 입력의 존재를 판정하지 않습니다. required 규칙은 빈 배열과 객체를 거부합니다. 숫자 0과 불리언 false는 해당 규칙에서 유효한 입력 값입니다. 컬렉션 개수와 표시 여부는 별도 계약이며 빈 컬렉션을 참고합니다.

6. 불리언 변환

null, 누락된 값, false, 숫자 0, 빈 문자열은 거짓입니다. "0"과 "false"를 포함한 비어 있지 않은 문자열은 참입니다. 배열과 객체는 빈 배열·빈 객체를 포함해 참입니다.

7. 와일드카드

items.*.name 같은 경로는 반복 항목을 해석합니다. 기본 평가는 필드 컨텍스트가 현재 행 인덱스를 제공하면 이를 사용합니다. 그렇지 않으면 남은 와일드카드를 후보 값으로 해석하며 하나라도 일치하면 비교가 참입니다. TypeScript 경로 평가기는 명시적인 ANY·ALL 전략도 제공하지만 해당 옵션은 공통 표현식 진입점의 계약에 포함하지 않습니다.

8. 조건맵

조건맵은 기본 키 외의 키를 선언 순서대로 평가해 처음 일치한 값을 반환합니다. 리터럴 키 true는 위치와 관계없이 다른 조건이 모두 실패한 후 기본값을 제공합니다. 일치한 조건과 기본값이 모두 없으면 null을 반환합니다.

class:
  ".status == 'active'": status-active
  ".status == 'pending'": status-pending
  true: status-default

맵 값은 표현식 평가 없이 반환합니다. 기본 키가 아닌 각 키는 단독 조건과 같은 파서·평가기에서 처리합니다.

9. 검증

네 언어와 PHP 확장은 같은 표현식 고정 사례를 불러와 토큰열, 직렬화한 AST, 불리언 결과, 값 결과를 비교합니다. 거부하는 표현식은 파싱 오류 메시지로 비교하며 메시지를 보고하지 않는 확장은 파싱에 실패하는지만 확인합니다. 사례 생성기는 TypeScript 출력을 기록하며 적합성 검사는 각 구현을 다시 실행해 기대 결과와 비교합니다. 생성만으로 정확성이 입증되지는 않습니다. 기대 의미는 이 계약과 일치해야 합니다. 구현과 테스트 결과는 기능 상태에 기록합니다.

10. 지원하지 않는 연산

산술 · 함수 호출 · 메서드 호출 · 정규식 평가 · 대입 · 비트 연산 · 슬래시로 시작하는 루트 경로 · eval.

검증 규칙은 표현식 엔진과 별도로 정규식 매개변수를 받을 수 있습니다. 동작 스크립트는 조건 평가와 별도로 처리합니다.