การเรนเดอร์th-TH

Grammar

ไวยากรณ์อย่างเป็นทางการของภาษาโปรแกรม Faber ไฟล์นี้เป็นพื้นผิวอ้างอิงหลักของไวยากรณ์และคำอธิบายประกอบภาษา ตัวอย่างที่รันได้อยู่ในคลังตัวอย่างสาธารณะ

โครงสร้างโปรแกรม#

ไฟล์ต้นฉบับ Faber เป็นข้อความดิบที่ตัวขับจะลอก frontmatter ก่อนการวิเคราะห์คำ โทเค็น TOML ไม่อยู่ในไวยากรณ์โทเค็นของภาษา

fabFile       := frontmatter? program
frontmatter   := '+++' NEWLINE tomlBody NEWLINE '+++' NEWLINE?
program       := statement*
statement     := importDecl | varDecl | funcDecl | genusDecl | implendumDecl
               | typeAliasDecl | enumDecl | discretioDecl
               | ifStmt | whileStmt | iteraStmt
               | eligeStmt | discerneStmt | guardStmt | curaStmt | facBlockStmt
               | returnStmt | breakStmt | continueStmt | noopStmt | throwStmt
               | assertStmt | outputStmt | adStmt | incipitStmt
               | incipietStmt | extractStmt
               | probandumDecl | probaStmt | blockStmt | incDecStmt | exprStmt
blockStmt     := '{' statement* '}'

Frontmatter ของไฟล์ (+++)#

ถ้ามี frontmatter ต้องเปิดที่ บรรทัด 1 ด้วย +++ ที่ตรงกันทุกตัว บรรทัดภายหลังซึ่งตัดช่องว่างแล้วเหลือ +++ จะปิดบล็อก ไบต์หลังตัวปิดคือ program ของ Faber เนื้อหาว่างหรือมีเพียงช่องว่างถือเป็นโปรแกรมว่างที่ถูกต้อง

ตัวขับคอมไพเลอร์อ่าน frontmatter เป็นเอกสาร TOML ทั่วไป ไม่ใช่คำสั่ง Faber ผู้เขียนใส่คีย์เมทาดาทาได้ตามต้องการ เครื่องมืออ่านคีย์ที่รู้จัก เช่น group, sectio และ [probanda] เครื่องมือแพ็กเกจ faber อ่านคีย์แพ็กเกจจากส่วนนี้ แต่ [package], [paths] และ [build] ยังคงอยู่ใน faber.toml; ถ้าค่าใน frontmatter ขัดแย้งในโหมดแพ็กเกจ ระบบจะปฏิเสธ

ตัวอย่าง:

+++
group = "exempla.directiva"
sectio = "smoke"
+++

เริ่ม {}

คำสั่งไฟล์ที่เริ่มบรรทัดด้วย § ถูกนำออกแล้ว ให้ใส่เมทาดาทาไฟล์ใน frontmatter +++ แทน ภายในสตริงที่มีเครื่องหมายคำพูด § ยังคงเป็นช่องของเทมเพลตสตริง

---

การประกาศ#

ตัวแปร#

varDecl      := ('คงที่' | 'แปร') typeAnnotation IDENTIFIER (('←' expression) | ('↤' assignment inlineRecovery?))?
sitDecl      := 'อนุมานคงที่' IDENTIFIER ('←' expression)?
arrayDestruct := ('คงที่' | 'แปร') arrayPattern '←' expression
objectDestruct := ('คงที่' | 'แปร') objectPattern '←' expression
  • คงที่ คือการผูกแบบแก้ไม่ได้ เขียนได้ครั้งเดียว; แปร คือการผูกที่กำหนดค่าใหม่ได้
  • ใช้ _ เป็นคำอธิบายชนิดเมื่อชนิดมาจากค่าเริ่มต้น: คงที่ _ name ← value
  • อนุมานคงที่ name ← value เป็นรูปย่อของ คงที่ _ name ← value
  • อนุมานคงที่ name โดยไม่มีค่าเริ่มต้นเป็นช่องคงที่ที่อนุมานชนิดภายหลัง ต้องกำหนดก่อนอ่าน
  • การเริ่มต้นแบบเลื่อนกำหนดค่าได้เพียงครั้งเดียว ระบบตรวจการกำหนดค่าครบถ้วนใน semantic Phase 3a

ฟังก์ชัน#

funcDecl     := 'ฟังก์ชัน' IDENTIFIER genericParams? '(' paramList ')' funcModifier* returnClause? alternateExitClause? blockStmt?
paramList    := (parameter (',' parameter)*)?
genericParams := '<' genericParam (',' genericParam)* '>'
genericParam := IDENTIFIER | 'ขนาด' IDENTIFIER
typeArgs     := '<' typeAnnotation (',' typeAnnotation)* '>'
parameter    := ('จาก' | 'ใน' | 'ออก')? 'ที่เหลือ'? typeAnnotation IDENTIFIER 'สมัครใจ'? ('ในชื่อ' IDENTIFIER)? ('หรือ' expression)?
funcModifier := 'อาร์กิวเมนต์' IDENTIFIER | 'จัดการ' IDENTIFIER ('ในชื่อ' IDENTIFIER)? | 'ข้อผิดพลาด' IDENTIFIER | 'ทางออก' (IDENTIFIER | NUMBER) | 'ไม่เปลี่ยนแปลง' | 'โยนผล' | 'ตัวเลือก' IDENTIFIER
returnClause := '→' typeAnnotation
alternateExitClause := '⇥' typeAnnotation
stmtBodyJoint  := 'ดังนั้น'
clausuraJoint  := '∴'
clausuraExpr   := compactClausuraExpr | legacyClausuraExpr
compactClausuraExpr := clausuraSignature clausuraJoint (expression | closureFacBlock)
clausuraSignature := (clausuraParam | '(' clausuraParams? ')') returnClause? alternateExitClause?
closureFacBlock := 'ทำ' blockStmt catchClause?
legacyClausuraExpr := 'ปิดล้อม' clausuraParams? ('→' typeAnnotation)? (':' expression | blockStmt)
clausuraParams := clausuraParam (',' clausuraParam)*
clausuraParam  := typeAnnotation IDENTIFIER

ประกาศชนิดผลสำเร็จปกติ ฟังก์ชันที่มีบอดีแต่ไม่มี เป็นฟังก์ชันผลข้างเคียง (ว่างเปล่า) และห้ามมี คืน บอดีแบบคำสั่งต้องเขียน → T ก่อนใช้ คืน; บอดีแบบนิพจน์อนุมานชนิดผลได้

ประกาศชนิดของช่องทางข้อผิดพลาด ฟังก์ชันหรือ closure ที่ใช้ โยน ออกจากขอบเขตต้องประกาศ ⇥ E ของตนเอง ขอบเขต ทำ { ... } จับ err { ... } จับ โยน ในพื้นที่ได้โดยไม่ต้องมี ภายนอก

คำนำหน้าพารามิเตอร์คือ จาก (อ่าน), ใน (แก้ไข), ออก (ใช้หมด); สมัครใจ เป็นตัวทำเครื่องหมายหลังชื่อ; ที่เหลือ ทำเครื่องหมายพารามิเตอร์ส่วนที่เหลือ; จัดการ ประกาศความต้องการตัวจัดสรร; ดังนั้น ใช้เฉพาะบอดีคำสั่งหนึ่งคำสั่ง และ ใช้เฉพาะข้อต่อ clausura เท่านั้น

คลาส#

genusDecl    := 'นามธรรม'? 'ชนิด' IDENTIFIER typeParams? ('สืบทอด' IDENTIFIER)? ('เติมเต็ม' IDENTIFIER (',' IDENTIFIER)*)? '{' genusMember* '}'
genusMember  := annotation* (fieldDecl | methodDecl)
fieldDecl    := 'ของชนิด'? 'ผูก'? typeAnnotation IDENTIFIER 'สมัครใจ'? ('=' expression)?
methodDecl   := 'ฟังก์ชัน' IDENTIFIER '(' paramList ')' funcModifier* returnClause? alternateExitClause? blockStmt?

คำกำกับ#

annotation            := '@' annotationName annotationBody?
annotationName        := IDENTIFIER | 'สาธารณะ' | 'ป้องกัน' | 'ส่วนตัว' | 'อนาคต' | 'ตัวชี้'
                        | 'แท็ก' | 'เฉพาะ' | 'ละเว้น' | 'วัด'
annotationBody        := bracedAnnotation | annotationArgs
bracedAnnotation      := '{' annotationFieldList? '}'
annotationFieldList   := annotationField (',' annotationField)* ','?
annotationField       := IDENTIFIER '=' (expression | typeAnnotation)
cliProgramAnnotation := '@' 'cli' STRING
imperiumAnnotation := '@' 'คำสั่ง' STRING
optioAnnotation    := '@' 'ตัวเลือก' IDENTIFIER optioModifier*
optioModifier      := 'สั้น' STRING | 'ยาว' STRING | 'ชนิด' typeAnnotation
                    | 'คำอธิบาย' STRING | 'ทั่วถึง' | 'หรือ' expression
operandusAnnotation := '@' 'ตัวถูกดำเนินการ' ('ที่เหลือ')? typeAnnotation IDENTIFIER operandusModifier*
operandusModifier  := 'คำอธิบาย' STRING | 'ทั่วถึง' | 'หรือ' expression
annotationArgs     := (STRING | IDENTIFIER | expression)+
annotatioMarker     := '@' 'annotation' ( '{' annotatioFieldList? '}' )?
annotatioFieldList  := annotatioField (',' annotatioField)* ','?
annotatioField      := 'เป้าหมาย' '=' annotatioTarget
annotatioTarget     := 'ฟังก์ชัน' | STRING | IDENTIFIER
contractApplication := '@' IDENTIFIER ( '{' annotationFieldList? '}' )?
jsonGenusAnnotation := '@' 'json'
jsonFieldAnnotation := '@' 'json' '{' 'ชื่อ' '=' STRING '}'

@ annotation ใช้ทำเครื่องหมาย ชนิด ระดับบนสุดเป็นสัญญา annotation ตอนคอมไพล์ สัญญา JSON ใช้ @ json กับ ชนิด และต้องมีฟิลด์ที่ปลอดภัยต่อ JSON

คำอธิบาย annotation ที่สำคัญ: @ radix สงวนไว้สำหรับเมทาดาทาคอมไพเลอร์, @ verte กำหนดการแปลงโค้ด, @ nondum ทำเครื่องหมายการประกาศที่ยังใช้ไม่ได้กับเป้าหมาย, @ cli ทำเครื่องหมายรายการ เริ่ม เป็นโปรแกรม CLI, @ คำสั่ง ทำเครื่องหมายจุดเข้า CLI, @ ตัวเลือก สร้างออปชัน, @ ตัวถูกดำเนินการ สร้างอาร์กิวเมนต์ตำแหน่ง, @ อนาคต ทำเครื่องหมาย async และ @ ตัวชี้ ทำเครื่องหมาย generator

สืบทอด หมายถึง extends, เติมเต็ม หมายถึง implements, ของชนิด หมายถึง static และ ผูก หมายถึง bound/property

อินเทอร์เฟซ#

implendumDecl   := 'สัญญา' IDENTIFIER typeParams? '{' implendumMethod* '}'
implendumMethod := annotation* 'ฟังก์ชัน' IDENTIFIER '(' paramList ')' funcModifier* returnClause? alternateExitClause?

สัญญา คือโครงสร้าง contract: เมธอดมีเฉพาะลายเซ็นและต้องถูกเติมเต็มด้วย เติมเต็ม ขอบเขตนำเข้าคือขอบเขตไฟล์ .fab; การประกาศที่ส่งออกอยู่ระดับบนสุดของไฟล์

นามแฝงชนิด#

typeAliasDecl := 'ชนิดนามแฝง' IDENTIFIER genericParams? '=' typeAnnotation

ลำดับค่า#

enumDecl   := 'ลำดับ' IDENTIFIER '{' enumMember (',' enumMember)* ','? '}'
enumMember := IDENTIFIER ('=' ('-'? NUMBER | STRING))?

สหภาพแบบติดป้าย#

discretioDecl := 'สหภาพแยก' IDENTIFIER typeParams? '{' variant (',' variant)* ','? '}'
variant       := IDENTIFIER ('{' variantFields '}')?
variantFields := (typeAnnotation IDENTIFIER (',' typeAnnotation IDENTIFIER)*)?

การตั้งชื่อ Identifier#

ชื่อแบบผสมตัวพิมพ์เล็กขึ้นต้นยอมรับทางไวยากรณ์ แต่ไม่ใช่รูปแบบที่แนะนำสำหรับภาษา ไลบรารีมาตรฐาน เส้นทางโฮสต์ หรือ API intrinsic ที่คอมไพเลอร์เป็นเจ้าของ ให้ใช้คำเดียวก่อน หากจำเป็นใช้ snake_case เฉพาะกรณีหายาก

การนำเข้า#

importDecl     := importRecord | importSugar
importRecord   := 'นำเข้า' '{' importFieldList? '}'
importFieldList := importField (',' importField)* ','?
importField    := importSourceField | importVisibilityField | importNameField
                | importAliasField | importWildcardField
importSourceField := 'ออก' '=' STRING
importVisibilityField := 'ทัศนวิสัย' '=' visibility
importNameField := 'ชื่อ' '=' IDENTIFIER
importAliasField := 'ในชื่อ' '=' IDENTIFIER
importWildcardField := 'ทั้งหมด' '=' IDENTIFIER
importSugar    := 'นำเข้า' 'ออก' STRING visibility? (namedImport | wildcardImport)?
visibility    := 'ส่วนตัว' | 'สาธารณะ'
namedImport   := IDENTIFIER ('ในชื่อ' IDENTIFIER)?
wildcardImport := '*' 'ในชื่อ' IDENTIFIER

ตัวอย่าง:

นำเข้า ออก "hono" ส่วนตัว Hono
นำเข้า ออก "norma:chorda"
นำเข้า { ออก = "norma:json/แก้", ในชื่อ = solve_mod }
นำเข้า ออก "faber:*" ส่วนตัว faber
นำเข้า ออก "./types" สาธารณะ User

ถ้าไม่ระบุทัศนวิสัย ค่าเริ่มต้นคือ ส่วนตัว ถ้าไม่ระบุ binding ที่มีชื่อ จะอนุมานจากส่วนสุดท้ายของเส้นทางเมื่อเป็น identifier ที่ถูกต้องและไม่ชนกับชื่อเดิม

---

ชนิด#

typeAnnotation := ('จาก' | 'ใน')? baseType ( '∪' typeAnnotation )*
baseType       := holeType | functionType | qualifiedType typeParams? | '(' typeAnnotation ')'
holeType       := '_' | '∪'
qualifiedType  := IDENTIFIER ('.' IDENTIFIER)*
functionType   := '(' typeList? ')' '→' typeAnnotation alternateExitClause?
typeList       := typeAnnotation (',' typeAnnotation)*
typeParams     := genericParams

อาร์เรย์เขียนเป็น รายการ<T> ไม่รับ T[]; จาก และ ใน ใช้ทำเครื่องหมาย ownership; T ∪ ว่าง คือรูป nullable มาตรฐาน; สมัครใจ เป็นตัวทำเครื่องหมายการประกาศ ไม่ใช่คำนำหน้าชนิด; เส้นทางชนิดแบบมี namespace ต้องแก้ prefix เป็น namespace ก่อน

ตัวอย่างชนิดฟังก์ชัน:

ฟังก์ชัน กรอง((T) → ตรรกะ pred) → รายการ<T>
ฟังก์ชัน ผสม((A) → B f, (B) → C g) → (A) → C
ฟังก์ชัน ใช้((จำนวน) → จำนวน ⇥ ข้อความ op, จำนวน n) → จำนวน ⇥ ข้อความ

ชนิดพื้นฐาน#

Faberความหมาย
ข้อความสตริง Unicode
asciiสตริง ASCII เท่านั้น
รูปแบบเทมเพลตที่จับพร้อมพารามิเตอร์
จำนวนจำนวนเต็ม ค่าเริ่มต้น i64
โมดูลัส<W>คำแบบไม่ติดลบที่คำนวณแบบโมดูลัส
เศษจำนวนลอยตัว ค่าเริ่มต้น f64
ตรรกะบูลีน
ว่างค่า null
เปล่าvoid
ไม่เคยnever
ไม่รู้unknown
ไบต์ไบต์

ชนิดที่กำหนดขนาดรับ width marker ตามตระกูล: จำนวน<W> ใช้ i8, i16, i32, i64, u8, u16, u32, u64; เศษ<W> ใช้ f16, f32, f64; โมดูลัส<W> ใช้ u8, u16, u32, u64 เท่านั้น

คอลเลกชันแบบทั่วไป#

Faberความหมาย
รายการ<T>อาร์เรย์
ตาราง<K,V>แมป
ชุด<T>เซต
คำมั่น<T>promise
ตัวชี้<T>iterator
tensor<T, Figura>บัฟเฟอร์เนื้อเดียวแบบหนาแน่น
vector<T, N>เวกเตอร์ตัวเลขแบบ register
matrix<T, [R, C]>เมทริกซ์ตัวเลขสองมิติ
atomic<T>เซลล์อะตอมิก
sparsa<T, Figura>บัฟเฟอร์ sparse

Figura คือ _ หรือขนาดธรรมชาติหรือ identifier หรือรายการใน []; tensor<T, []> คือ rank 0; vacua ให้คอลเลกชันว่างตามชนิดบริบท; matrix ต้องมีสองมิติ; atomic<T> ใน v1 รับ i32 หรือ u32; การสร้างค่าคอลเลกชันใช้ crea, structa หรือ ไม่ใช้ Type(...)

น้ำตาลชนิด#

น้ำตาลอยู่ในตำแหน่งชนิดเท่านั้นและมีความหมายเดียวกับรูปเต็ม ตัวทำเครื่องหมายขนาดคือ i8u64 และ f16f64 รูปขึ้นต้นด้วย l หมายถึง รายการ, t หมายถึง tensor, s หมายถึง sparsa, v หมายถึง vector, m หมายถึง matrix น้ำตาล matrix ต้องมี shape สองมิติ และ โมดูลัส<W> ไม่มีน้ำตาล

---

การควบคุมการไหล#

เงื่อนไข#

ifStmt     := 'ถ้า' expression arm ('ถ้าไม่ก็' ifStmt | elseClause)?
elseClause := 'มิฉะนั้น' elseArm
arm        := (blockStmt | 'ดังนั้น' statement) catchClause?
elseArm    := (blockStmt | 'ดังนั้น' statement) catchClause?

ถ้า = if, ถ้าไม่ก็ = else-if, มิฉะนั้น = else, ดังนั้น ใช้กับบอดีหนึ่งคำสั่ง และ เงียบ ใช้แทน no-op แบบชัดเจน

ลูป#

whileStmt  := 'ขณะ' expression (blockStmt | 'ดังนั้น' statement) catchClause?
iteraStmt  := 'วน' (('ออก' | 'จาก') expression | 'จาก' expression) ('คงที่' | 'แปร') IDENTIFIER (blockStmt | 'ดังนั้น' statement) catchClause?

วน ออก...คงที่ คือ for-of, วน จาก...คงที่ คือ for-in และ วน จาก range คงที่ i คือการวนช่วง โดย ต่อ อยู่ในนิพจน์ช่วง

การเลือกกรณี#

eligeStmt    := 'เลือก' expression '{' eligeCase* defaultCase? '}' catchClause?
eligeCase    := 'กรณี' expression (blockStmt | 'ดังนั้น' statement)
defaultCase  := 'อื่น' (blockStmt | 'ดังนั้น' statement)

การจับคู่รูปแบบ#

discerneStmt := 'แยก' 'ทั้งหมด'? discriminants '{' variantCase* defaultCase? '}'
discriminants := expression (',' expression)*
variantCase  := 'กรณี' patterns (blockStmt | 'ดังนั้น' statement)
patterns     := pattern ((',' | 'และ') pattern)*
pattern      := '_' | literal | (IDENTIFIER patternBind?)
patternBind  := ('ในชื่อ' IDENTIFIER) | (('คงที่' | 'แปร') patternBinding (',' patternBinding)*)
patternBinding := IDENTIFIER ('ในชื่อ' IDENTIFIER)?

การป้องกัน#

guardStmt   := 'คุ้มครอง' '{' guardClause+ '}'
guardClause := 'ถ้า' expression (blockStmt | 'ดังนั้น' statement)

การจัดการทรัพยากร#

curaStmt    := 'ดูแล' STRING ('คงที่' | 'แปร') typeAnnotation IDENTIFIER blockStmt catchClause?

การแยกโครงสร้าง#

extractStmt   := 'ออก' expression ('คงที่' | 'แปร') extractFields
extractFields := extractField (',' extractField)* (',' restField)? | restField
extractField  := IDENTIFIER ('ในชื่อ' IDENTIFIER)?
restField     := 'ที่เหลือ' IDENTIFIER

การส่งต่อการควบคุม#

returnStmt   := 'คืน' expression?
breakStmt    := 'หยุด'
continueStmt := 'ไปต่อ'
noopStmt     := 'เงียบ'

---

การจัดการข้อผิดพลาด#

throwStmt   := ('โยน' | 'ตาย') expression ['ถ้า' expression]
catchClause := 'จับ' IDENTIFIER blockStmt
assertStmt  := 'ยืนยัน' expression ('secus' expression)?

จับ ต่อกับคำสั่งแบบมีโครงสร้างและแขนของเงื่อนไข ไม่ต่อกับบล็อกเปล่าโดยตรง ทำ { ... } จับ err { ... } เป็นขอบเขต recoverable แบบครั้งเดียว ลอง และ ท้าย เป็นพื้นผิวเก่าที่ถูกปฏิเสธ โยน คือข้อผิดพลาดที่กู้คืนได้ และ ตาย คือ panic ร้ายแรง guard ถ้า <expr> เป็นน้ำตาลของ parser

---

นิพจน์#

ตัวดำเนินการ (จากความสำคัญต่ำไปสูง)#

expression := assignment
assignment := ternary ('←' assignment | '↤' assignment inlineRecovery?)?
incDecStmt := place ('⊕' | '⊖')
ternary    := or (('?' expression ':' | 'เช่นนั้น' expression 'มิฉะนั้น') ternary)?
or         := and (('หรือ') and)*
and        := equality (('และ') equality)*
equality   := comparison (('≡' | '≠' | '≈' | '≉' | 'เป็น' | 'ไม่' 'เป็น') comparison)*
comparison := bitwiseOr (('<' | '>' | '≤' | '≥' | 'ภายใน' | 'ระหว่าง') bitwiseOr)*
bitwiseOr  := bitwiseXor ('∨' bitwiseXor)*
bitwiseXor := bitwiseAnd ('⊻' bitwiseAnd)*
bitwiseAnd := shift ('∧' shift)*
shift      := range (('⇐' | '⇒') range)*
range      := additive (('‥' | '…' | 'ก่อน' | 'จนถึง') additive ('ต่อ' additive)?)?
additive   := multiplicative (('+' | '-') multiplicative)*
multiplicative := coalesce (('*' | '/' | '%') coalesce)*
coalesce   := unary ('หรือ' velRhs)*
velRhs     := unary (('‥' | '…' | 'ก่อน' | 'จนถึง') unary ('ต่อ' unary)?)?
unary      := ('-' | '¬' | 'ไม่' | 'รอ' | 'สร้าง') unary | cast
cast       := call ('∷' typeAnnotation | conversio)*
conversio   := '↦' typeAnnotation inlineRecovery?
inlineRecovery := '⇥' unary

คือการกำหนดค่าแบบแปลงชนิดตามเป้าหมาย: ประเมินด้านขวา แปลงเป็นชนิดคงที่ของด้านซ้ายผ่านเส้นทาง แล้วกำหนดค่า สำหรับกู้คืนใช้ได้เฉพาะหลัง เท่านั้น ไม่ใช่หลัง

ตัวดำเนินการ glyph ต้องคงเดิมเสมอ คือการระบุชนิดแบบคอมไพล์ไทม์; คือการแปลงค่ารันไทม์; ใช้กู้คืนความล้มเหลวแบบอินไลน์ หรือ ใช้กำจัด nullable เฉพาะที่ ไม่ใช่คำพ้องของตรรกะ หรือ

การเรียกและการเข้าถึงสมาชิก#

call          := primary (callSuffix | memberSuffix | optionalSuffix | nonNullSuffix)*
callSuffix    := typeArgs? '(' argumentList ')'
memberSuffix  := '.' IDENTIFIER | '[' expression ']'
optionalSuffix := '?.' IDENTIFIER | '?[' expression ']' | '?(' argumentList ')'
nonNullSuffix := '!.' IDENTIFIER | '![' expression ']' | '!(' argumentList ')'
argumentList  := (argument (',' argument)*)?
argument      := 'กระจาย'? expression

สตริงและเทมเพลต#

Faber ใช้ความหมายตามตัวคั่น: แต่ละรูปแบบมีชนิดและบทบาทต่างกัน ไม่ใช่คำพ้องกัน

รูปแบบชนิดบทบาท
'...'asciiโทเค็นเครื่องคงที่
"..."ข้อความสตริง Unicode สั้น
«...»ข้อความสตริง Unicode หลายบรรทัด
... รูปแบบเทมเพลตที่จับ
{ ... }jsonเอกสาร JSON รากออบเจ็กต์
\|...\|ไบต์ไบต์ฐานสิบหก
"..." ↦ regexregexแพตเทิร์นคอมไพล์จากข้อความ
[ ... ]รายการ<T>รายการ Faber

§ เป็นช่องเทมเพลตในรูป Unicode (", «, และ backtick) และห้ามอยู่ใน literal ascii เทมเพลตที่เรนเดอร์ใช้ "..."(...) หรือ «...»(...); เทมเพลตที่จับใช้ ...(...) สำหรับ payload ที่ผูกกับ SQL/URL

ตัวอย่าง:

คงที่ _ tag ← «inline»
คงที่ _ q ← `select * from accounts where id = §`(accountId)
คงที่ _ sig ← |de ad be ef|
"สถานะ: § (§)"(sample_status(), "ok")

การเข้าถึงข้อความใช้ดัชนี Unicode-scalar; การเข้าถึง รายการ<T> ใช้ดัชนีจำนวนเต็มเดี่ยวและ trap เมื่อเกินขอบเขต; การอ่าน tensor คืน T ∪ ว่าง; ไบต์ ไม่รับวงเล็บเหลี่ยมและใช้เมธอด accipe, appende, longitudo

นิพจน์หลัก#

primary := IDENTIFIER | NUMBER | STRING | ASCII_STRING | BACKTICK_STRING
         | 'ตัวฉัน' | 'จริง' | 'เท็จ' | 'ว่าง'
         | 'ว่างเปล่า' | arrayLiteral | jsonLiteral | typedConstructor
         | adExpr
         | '(' expression ')'
adExpr    := 'ถึง' asciiLiteral adOpener?
arrayLiteral := '[' argumentList? ']'
jsonLiteral := '{' (jsonMember (',' jsonMember)* ','?)? '}'
jsonMember  := STRING ':' jsonValue
typedConstructor := typeAnnotation '{' fieldList? '}'
fieldList := fieldInit (',' fieldInit)*
fieldInit := ('กระจาย' expression) | (fieldKey '=' expression) | IDENTIFIER
fieldKey := IDENTIFIER | STRING | '[' expression ']'
jsonValue := jsonObject | jsonArray | jsonString | jsonNumber | 'true' | 'false' | 'null'
jsonObject := '{' (jsonMember (',' jsonMember)* ','?)? '}'
jsonArray := '[' (jsonValue (',' jsonValue)* ','?)? ']'
jsonString := STRING
jsonNumber := NUMBER

นิพจน์พิเศษ#

fingeExpr     := 'สร้าง' IDENTIFIER ('{' fieldList '}')? ('∷' IDENTIFIER)?
praefixumExpr := 'นำหน้า' (blockStmt | '(' expression ')')
formatStringExpr := STRING '(' argumentList ')'
formaTemplateExpr := BACKTICK_STRING '(' argumentList ')'
scriptumExpr  := 'จารึก' '(' STRING (',' expression)* ')'
legeExpr      := 'อ่าน' 'บรรทัด'?
regexFromText := (STRING | ASCII_STRING) '↦' 'regex'

รูป regex แบบ /.../ ยังไม่อยู่ในไวยากรณ์ ตัวดำเนินการ / ยังคงเป็นการหาร และคอมเมนต์ // กับ /* ... */ ถูกปฏิเสธ

---

รูปแบบจับคู่#

objectPattern  := '{' patternProperty (',' patternProperty)* '}'
patternProperty := 'ที่เหลือ'? IDENTIFIER ('ในชื่อ' IDENTIFIER)?
arrayPattern   := '[' arrayPatternElement (',' arrayPatternElement)* ']'
arrayPatternElement := '_' | 'ที่เหลือ'? IDENTIFIER

---

การวินิจฉัย#

outputStmt := ('บันทึก' | 'ดู' | 'เตือน' | 'เขียน') expression (',' expression)*

บันทึก คือหมายเหตุทั่วไป, ดู คือ debug/inspect, เตือน คือ warning และ เขียน คือช่องวินิจฉัย การส่งผลจริงให้ใช้เมธอดไลบรารีมาตรฐาน

คอมเมนต์#

Faber รับเฉพาะคอมเมนต์บรรทัด: # ถึงจบบรรทัด # ต้องเป็นโทเค็นที่ไม่ใช่ช่องว่างตัวแรกของบรรทัดตรรกะ คอมเมนต์ที่อยู่หลังโทเค็นอื่นในบรรทัดเดียวกันเป็น lex error # ใน literal ที่มีตัวคั่นไม่ใช่คอมเมนต์

---

จุดเข้า#

incipitStmt  := 'เริ่ม' blockStmt
incipietStmt := 'เริ่มอะซิงก์' blockStmt

เริ่ม คือจุดเข้าแบบ sync และ เริ่มอะซิงก์ คือจุดเข้าแบบ async

---

การทดสอบ#

probandumDecl := 'ทดสอบชุด' STRING probaModifier* '{' probandumBody '}'
probandumBody := (praeparaBlock | probandumDecl | probaStmt)*
probaStmt     := 'ทดสอบ' STRING probaModifier* blockStmt
probaModifier := 'ละเว้น' STRING | 'อนาคต' STRING | 'เฉพาะ' | 'แท็ก' STRING
              | 'เวลา' NUMBER | 'วัด' | 'ทำซ้ำ' NUMBER | 'เปราะบาง' NUMBER
              | 'ต้องการ' STRING | 'เฉพาะใน' STRING
praeparaBlock := ('เตรียม' | 'จะเตรียม' | 'หลังเตรียม' | 'จะหลังเตรียม') 'ทั้งหมด'? blockStmt

---

เฟรมเวิร์ก CLI#

cliDecl       := annotation* (incipitStmt | funcDecl)
cliAnnotation := cliProgramAnnotation | imperiumAnnotation | optioAnnotation | operandusAnnotation

Faber รองรับการสร้างแอป CLI พร้อมการแยกอาร์กิวเมนต์และการสร้างความช่วยเหลืออัตโนมัติ

@ cli "faber"
@ ตัวเลือก verbose ยาว "verbose" ชนิด ตรรกะ
เริ่ม อาร์กิวเมนต์ args {
    # เฟรมเวิร์ก CLI แยกอาร์กิวเมนต์อัตโนมัติ
}

---

การเรียก Capability#

รูปนิพจน์ ถึง เป็นพื้นผิว ad ที่รองรับเพียงแบบเดียว รูปเก่าแบบมีชนิดและบล็อกสตรีมถูกปฏิเสธตอน parse

adExpr        := 'ถึง' asciiLiteral adOpener?
adOpener      := '(' expression ')'
conversioExpr := expr '↦' typeAnnotation

เส้นทางต้องเป็น asciiLiteral; opener เป็นนิพจน์เดียวที่ส่งเป็น data; นิพจน์ ถึง คืน handle การสนทนา sermo; ใช้ ↦ T เพื่อ materialize หรือใช้มุมมอง s.meus<T>() และ s.tuus<T>() รูปเก่าทั้งหมดเป็น parse error ชนิดที่คอมไพเลอร์เป็นเจ้าของคือ scrinium, status, และ handle ทึบแสง sermo

---

การดำเนินการกับคอลเลกชัน#

DSL pipeline ab แบบเก่าถูกยกเลิก การกรอง การตัด และการรวมใช้เมธอดปกติของ ข้อความ, รายการ, ตาราง, ชุด และ closure แทน prima และ ultima เป็นชื่อเมธอดทั่วไป และ ubi ไม่ใช่ไวยากรณ์คอลเลกชันที่ใช้งานอยู่

---

บล็อก ทำ#

facBlockStmt := 'ทำ' blockStmt catchClause? ('ขณะ' expression)?

ทำ { ... } ทำงานครั้งเดียว; ทำ { ... } จับ err { ... } เป็นขอบเขตข้อผิดพลาดที่กู้คืนได้; ทำ { ... } ขณะ condition เป็นลูป post-test และ ขณะ ต่อท้ายได้เฉพาะ ทำ

---

การรองรับเป้าหมาย#

การรองรับเป้าหมายไม่ใช่ส่วนของไวยากรณ์ ไฟล์นี้กำหนดเฉพาะภาษา สำหรับตาราง grammar×target ให้ดู EBNF_MATRIX.md และนโยบายรันไทม์ให้ดูเอกสาร target capability matrix

---

อ้างอิงคำสำคัญ#

ตารางนี้สรุปพื้นผิวคำสำคัญสำหรับผู้อ่านภาษาไทย คำสำคัญในตัวอย่างใช้การสะกดเดียวกับภาคผนวกท้ายเอกสาร คำที่เป็น glyph เช่น , , , , , , , , , , , , , , , , , , , ¬ คงเดิมเสมอ

หมวดพื้นผิวภาษาไทยความหมาย
การประกาศคงที่, แปร, ฟังก์ชัน, ชนิด, สัญญา, ลำดับ, สหภาพแยกการประกาศค่าคงที่ ตัวแปร ฟังก์ชัน ชนิด อินเทอร์เฟซ enum และ tagged union
การควบคุมถ้า, ถ้าไม่ก็, มิฉะนั้น, ขณะ, วน, เลือก, กรณี, แยก, คุ้มครอง, ทำเงื่อนไข ลูป การเลือก การจับคู่ และขอบเขตการจัดการข้อผิดพลาด
การส่งต่อคืน, หยุด, ไปต่อ, เงียบ, โยน, ตาย, จับreturn, break, continue, no-op, throw, panic และ handler
นิพจน์และ, หรือ, ไม่, เป็น, ภายใน, ระหว่าง, ก่อน, จนถึง, ต่อ, หรือว่างตัวดำเนินการตรรกะ การเปรียบเทียบ ช่วง และการกำจัด nullable
การทดสอบทดสอบ, ทดสอบชุด, เตรียม, จะเตรียม, หลังเตรียม, จะหลังเตรียมการประกาศและตัวปรับแต่งการทดสอบ

---

กฎไวยากรณ์สำคัญ#

  1. พารามิเตอร์ใช้ชนิดก่อนชื่อ: ฟังก์ชัน f(จำนวน x) ไม่ใช่ ฟังก์ชัน f(x: จำนวน)
  2. การประกาศใช้ชนิดก่อนชื่อ: คงที่ ข้อความ name ไม่ใช่ คงที่ name: ข้อความ
  3. ลูปใช้รูป วน ออก/จาก collection คงที่/แปร item { } หรือ วน จาก range คงที่/แปร item { }
  4. วงเล็บรอบเงื่อนไขใช้ได้ แต่ไม่ใช่รูปที่แนะนำ
  5. คำวินิจฉัยเป็นคำสั่ง ไม่ใช่ค่าที่เรียกได้

Reader pack glossary (machine extract)#

Keywords#

LatinLocalized
discretioสหภาพแยก
fixumคงที่
functioฟังก์ชัน
genusชนิด
implendumสัญญา
importaนำเข้า
modulusโมดูลัส
ordoลำดับ
sitอนุมานคงที่
typusชนิดนามแฝง
variaแปร
abstractusนามธรรม
ceteriที่เหลือ
curataจัดการ
errataข้อผิดพลาด
exitusทางออก
generisของชนิด
iacitโยนผล
immutataไม่เปลี่ยนแปลง
magnitudoขนาด
nexumผูก
optionesตัวเลือก
praeก่อนหน้า
privataส่วนตัว
protectaป้องกัน
publicaสาธารณะ
sponteสมัครใจ
casuกรณี
ceterumอื่น
custodiคุ้มครอง
discerneแยก
dumขณะ
eligeเลือก
ergoดังนั้น
facทำ
iteraวน
secusมิฉะนั้น
siถ้า
sicเช่นนั้น
sinถ้าไม่ก็
pergeไปต่อ
reddeคืน
rumpeหยุด
tacetเงียบ
adfirmaยืนยัน
capeจับ
cedeรอ
iaceโยน
moriตาย
clausuraปิดล้อม
falsumเท็จ
nihilว่าง
verumจริง
autหรือ
estเป็น
etและ
nonไม่
velหรือว่าง
egoตัวฉัน
fingeสร้าง
impletเติมเต็ม
subสืบทอด
moneเตือน
notaบันทึก
scribeเขียน
videดู
argumentaอาร์กิวเมนต์
curaดูแล
incipietเริ่มอะซิงก์
incipitเริ่ม
adถึง
deจาก
exออก
inใน
legeอ่าน
lineamบรรทัด
omniaทั้งหมด
praefixumนำหน้า
scriptumจารึก
spargeกระจาย
utในชื่อ
anteก่อน
interระหว่าง
intraภายใน
perต่อ
usqueจนถึง
fragilisเปราะบาง
futurumอนาคต
metiorวัด
omitteละเว้น
postparaหลังเตรียม
postparabitจะหลังเตรียม
praeparaเตรียม
praeparabitจะเตรียม
probaทดสอบ
probandumทดสอบชุด
repeteทำซ้ำ
requiritต้องการ
solumเฉพาะ
solum_inเฉพาะใน
tagแท็ก
temporisเวลา
negativumลบ
nonnihilไม่ว่าง
nonnullaไม่เป็นค่าว่าง
nullaว่างเปล่า
positivumบวก

Types#

LatinLocalized
asciiascii
textusข้อความ
numerusจำนวน
modulusโมดูลัส
fractusเศษ
bivalensตรรกะ
nihilว่าง
vacuumเปล่า
numquamไม่เคย
ignotumไม่รู้
octetiไบต์
regexregex
jsonjson
valorค่า
instansอินสแตนซ์
objectumออบเจ็กต์
quidlibetอะไรก็ได้
listaรายการ
tabulaตาราง
copiaชุด
promissumคำมั่น
cursorตัวชี้

Glossary changes vs pass1 / existing pack#

LatinOld packNew (this EBNF)Why
fixumคงที่คงที่คงคำเดิม
functioฟังก์ชันฟังก์ชันคงคำเดิม
genusชนิดชนิดคงคำเดิม
variaแปรแปรคงคำเดิม
importaนำเข้านำเข้าคงคำเดิม
siถ้าถ้าคงคำเดิม
sinถ้าไม่ก็ถ้าไม่ก็คงคำเดิม
secusมิฉะนั้นมิฉะนั้นคงคำเดิม
dumขณะขณะคงคำเดิม
facทำทำคงคำเดิม
iteraวนวนคงคำเดิม
pergeข้ามไปต่อปรับให้ตรงความหมาย continue
rumpeหยุดหยุดคงคำเดิม
reddeคืนคืนคงคำเดิม
casuกรณีกรณีคงคำเดิม
ceterumอื่นอื่นคงคำเดิม
eligeเลือกเลือกคงคำเดิม
discerneแยกแยกคงคำเดิม
capeจับจับคงคำเดิม
falsumเท็จเท็จคงคำเดิม
verumจริงจริงคงคำเดิม
nihilว่างว่างคงคำเดิม
etและและคงคำเดิม
autหรือหรือคงคำเดิม
nonไม่ไม่คงคำเดิม
estเป็นเป็นคงคำเดิม
notaแสดงบันทึกปรับให้สอดคล้องกับบทบาท diagnostic note
moneเตือนเตือนคงคำเดิม
scribeเขียนเขียนคงคำเดิม
videดูดูคงคำเดิม
incipitเริ่มเริ่มคงคำเดิม
argumentaอาร์กิวเมนต์อาร์กิวเมนต์คงคำเดิม
exจากออกแยกความหมาย import source/consume ให้ชัด
deยืมจากให้สอดคล้องกับการวนแบบ for-in
inในในคงคำเดิม
utในชื่อในชื่อคงคำเดิม
textusข้อความข้อความคงคำเดิม
numerusจำนวนจำนวนคงคำเดิม
fractusเศษเศษคงคำเดิม
bivalensตรรกะตรรกะคงคำเดิม
vacuumเปล่าเปล่าคงคำเดิม
ignotumไม่รู้ไม่รู้คงคำเดิม
listaรายการรายการคงคำเดิม
tabulaตารางตารางคงคำเดิม
copiaชุดชุดคงคำเดิม
cursorตัวชี้ตัวชี้คงคำเดิม

หมายเหตุสั้นเมื่อเทียบกับ pass1: ฉบับนี้เติมส่วนที่ขาดจาก EBNF ต้นฉบับ ปรับหัวข้อและคำอธิบายที่ยังเป็นอังกฤษให้เป็นภาษาไทย ทำให้ ergo ใช้เป็นข้อต่อบอดีคำสั่งอย่างสม่ำเสมอ รักษา เป็น glyph ของ clausura เท่านั้น แก้ perge เป็น ไปต่อ และเพิ่ม glossary ครบ 111 คำสำคัญกับ 22 ชนิดโดยไม่มีการชนกันของการสะกดในแต่ละกลุ่ม