More refactor

This commit is contained in:
be5invis 2023-05-24 00:42:05 -07:00
parent 09d80208a8
commit 2890a4cd00
16 changed files with 1085 additions and 1436 deletions

View file

@ -695,7 +695,7 @@ i = "serifless"
j = "flat-hook-serifless"
k = "straight-serifless"
l = "serifless"
r = "compact"
r = "compact-serifless"
t = "flat-hook"
u = "toothed-serifless"
w = "straight-flat-top-serifless"
@ -727,7 +727,7 @@ i = "serifed"
j = "flat-hook-serifed"
k = "straight-serifless"
l = "serifed"
r = "compact"
r = "compact-serifless"
t = "flat-hook"
u = "toothed-serifless"
w = "straight-flat-top-serifless"

View file

@ -1,8 +1,10 @@
* \[**BREAKING**\] Add taller slash, broken slash and broken zero variants for Zero. As a result, current variants are reordered (#1307, #1509, #1678).
* \[**BREAKING**\] Add above-baseline crossed variant for Q. As a result, current variants are reordered (#1533).
* \[**BREAKING**\] Rectify the variant atlas. As a result, if a character's variant list has motion-serifed, then it will have serifless and serifed variants: the serifed-ness will no longer be controlled by SLAB variable. The characters influenced are `M`, `N`, `P`, `R`, `U`, `V`, `W`, `b`, `h`, `m`, `n`, `p`, `q`, `u`, `v`, `w`, `y`.
* \[**BREAKING**\] Reordered the variants of the following letters:
* \[**BREAKING**\] Renamed and/or reordered the variants of the following letters:
- `K`, `k`, Cyrillic Ka.
- `r`.
- `W`, `w`.
* Add Characters:
- CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN (`U+29BC`).
- CIRCLED WHITE BULLET (`U+29BE`).

View file

@ -8,18 +8,11 @@ import [DesignParameters] from"../meta/aesthetics.mjs"
extern isFinite
import [mix linreg clamp fallback] from"../support/utils.mjs"
import [mix linreg clamp fallback $NamedParameterPair$] from"../support/utils.mjs"
import [calculateMetrics setFontMetrics GenDivFrame] from"../meta/aesthetics.mjs"
$$include '../meta/macros.ptl'
define [$NamedParameterPair$ l r] : begin
set this.left l
set this.right r
return this
define [$DoNothing$] nothing
export : define [buildGlyphs para recursive] : begin
local glyphStore : new GlyphStore
@ -110,7 +103,6 @@ export : define [buildGlyphs para recursive] : begin
$assignUnicodeImpl$
$defineGlyphBlockImpl$
$execState$
$DoNothing$
Metrics : Object.assign {.} Metrics
para
recursive

View file

@ -1,6 +1,6 @@
$$include '../../../meta/macros.ptl'
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
import [mix linreg clamp fallback SuffixCfg] from"../../../support/utils.mjs"
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
glyph-module
@ -149,29 +149,38 @@ glyph-block Letter-Latin-Lower-R : begin
curl (xBar - Stroke * HVContrast) 0 [heading Downward]
if doBottomSerif : include : rBottomSerif 0
define SmallRConfig : object
'serifless' { StandardShape dfN rStraight { 0 0 } }
'serifed' { StandardShape dfN rSerifed { 1 1 } }
'topSerifed' { StandardShape dfN rSerifed { 1 0 } }
'baseSerifed' { StandardShape dfN rSerifed { 0 1 } }
'earlessCorner' { EarlessCornerShape dfN rEarless { 0 0 } }
'earlessCornerSerifed' { EarlessCornerShape dfN rEarless { 0 1 } }
'earlessRounded' { EarlessRoundedShape dfN rEarless { 0 0 } }
'earlessRoundedSerifed' { EarlessRoundedShape dfN rEarless { 0 1 } }
'hookless' { CompactShape dfN rNarrow { 0 0 } }
'hooklessSerifed' { CompactShape dfN rNarrowSerifed { 1 1 } }
'hooklessTopSerifed' { CompactShape dfN rNarrowSerifed { 1 0 } }
'hooklessBaseSerifed' { CompactShape dfN rNarrowSerifed { 0 1 } }
'compact' { CompactShape dfR rNarrow { 0 0 } }
'compactSerifed' { CompactShape dfR rNarrowSerifed { 1 1 } }
'compactTopSerifed' { CompactShape dfR rNarrowSerifed { 1 0 } }
'compactBaseSerifed' { CompactShape dfR rNarrowSerifed { 0 1 } }
'cornerHooked' { CornerHookShape dfN rCornerHooked { 0 0 } }
'cornerHookedSerifed' { CornerHookShape dfN rCornerHookedSerifed { 1 1 } }
'cornerHookedTopSerifed' { CornerHookShape dfN rCornerHookedSerifed { 1 0 } }
'cornerHookedBaseSerifed' { CornerHookShape dfN rCornerHookedSerifed { 0 1 } }
define [FlapHooklessShape df md doTopSerif doBottomSerif] : glyph-proc
define [object xBar rBottomSerif xArchMiddle setMarks] : RDim df md
set-base-anchor 'overlay' (xBar - 0.5 * Stroke * HVContrast) (XH / 2)
include : setMarks doTopSerif
include : dispiro
widths.lhs
g4.left.start (xArchMiddle - CorrectionOMidS * [linreg 72 0.75 108 1 Stroke]) (XH - O)
archv
flat (xBar - Stroke * HVContrast) (XH - SmallArchDepthA)
curl (xBar - Stroke * HVContrast) 0 [heading Downward]
if doBottomSerif : include : rBottomSerif 0
foreach { suffix { F df mode { doTS doBS } } } [Object.entries SmallRConfig] : do
define SmallRConfig : SuffixCfg.weave
# Body
object
'' { StandardShape dfN rStraight }
earlessCorner { EarlessCornerShape dfN rEarless }
earlessRounded { EarlessRoundedShape dfN rEarless }
hookless { CompactShape dfN rNarrow }
cornerHooked { CornerHookShape dfN rCornerHooked }
compact { CompactShape dfR rNarrow }
hooklessFlap { FlapHooklessShape dfN rNarrow }
compactFlap { FlapHooklessShape dfR rNarrow }
# Serifs
object
serifless { 0 0 }
topSerifed { 1 0 }
baseSerifed { 0 1 }
serifed { 1 1 }
foreach { suffix { {F df mode} {doTS doBS} } } [pairs-of SmallRConfig] : do
create-glyph "r.\(suffix)" : glyph-proc
set-width df.width
include : df.markSet.e
@ -256,34 +265,5 @@ glyph-block Letter-Latin-Lower-R : begin
include : dfR.markSet.e
include : BBRShape dfN rStraight 0 0
create-glyph 'rFlap.serifless' : glyph-proc
set-width dfN.width
include : dfN.markSet.e
define [object rBottomSerif] : RDim dfN rEarless
include : EarlessRoundedShape dfN rEarless 0 0
create-forked-glyph 'rFlap.serifed' : rBottomSerif 0
define [rFlapHooklessShape df] : glyph-proc
include : df.markSet.e
define [object xBar rBottomSerif xArchMiddle] : RDim df rNarrow
set-base-anchor 'overlay' (xBar - 0.5 * Stroke * HVContrast) (XH / 2)
include : dispiro
widths.lhs
g4.left.start (xArchMiddle - CorrectionOMidS * [linreg 72 0.75 108 1 Stroke]) (XH - O)
archv
flat (xBar - Stroke * HVContrast) (XH - SmallArchDepthA)
curl (xBar - Stroke * HVContrast) 0 [heading Downward]
if SLAB : include : rBottomSerif 0
create-glyph 'rFlap.hookless' : glyph-proc
set-width dfN.width
include : rFlapHooklessShape dfN
create-glyph 'rFlap.compact' : glyph-proc
set-width dfR.width
include : rFlapHooklessShape dfR
select-variant 'rFlap' 0x27E
select-variant 'rFlap' 0x27E (shapeFrom -- 'r')
CreateAccentedComposition 'rFlapTildeOver' 0x1D73 'rFlap' 'tildeOver'

View file

@ -1,6 +1,6 @@
$$include '../../../meta/macros.ptl'
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
import [mix fallback SuffixCfg] from"../../../support/utils.mjs"
import [Dotless CvDecompose] from"../../../support/gr.mjs"
glyph-module
@ -207,26 +207,19 @@ glyph-block Letter-Latin-Lower-T : begin
include : VBar.m df.middle 0 top
include : HCrossBar.top df.middle (df.middle + df.div * LongJut) yCrossBar
define SmallTConfig : object
standard { [DivFrame 1] Standard Ascender }
diagonalTailed { dfNarrowT DiagTail Ascender }
flatHook { dfNarrowT Flat Ascender }
cross { dfNarrowT Cross Ascender }
hooklessAsymmetric { dfNarrowT HooklessAsymmetric Ascender }
define SmallTConfig :SuffixCfg.weave
object # body
standard { [DivFrame 1] Standard }
diagonalTailed { dfNarrowT DiagTail }
flatHook { dfNarrowT Flat }
cross { dfNarrowT Cross }
hooklessAsymmetric { dfNarrowT HooklessAsymmetric }
object # height
"" Ascender
shortNeck yShortNeck1
shortNeck2 yShortNeck2
standardShortNeck { [DivFrame 1] Standard yShortNeck1 }
diagonalTailedShortNeck { dfNarrowT DiagTail yShortNeck1 }
flatHookShortNeck { dfNarrowT Flat yShortNeck1 }
crossShortNeck { dfNarrowT Cross yShortNeck1 }
hooklessAsymmetricShortNeck { dfNarrowT HooklessAsymmetric yShortNeck1 }
standardShortNeck2 { [DivFrame 1] Standard yShortNeck2 }
diagonalTailedShortNeck2 { dfNarrowT DiagTail yShortNeck2 }
flatHookShortNeck2 { dfNarrowT Flat yShortNeck2 }
crossShortNeck2 { dfNarrowT Cross yShortNeck2 }
hooklessAsymmetricShortNeck2 { dfNarrowT HooklessAsymmetric yShortNeck2 }
foreach { suffix { df Style top } } [Object.entries SmallTConfig] : do
foreach { suffix { {df Style} top } } [pairs-of SmallTConfig] : do
create-glyph "t.\(suffix)" : glyph-proc
set-width df.width
include : df.markSet.b
@ -399,4 +392,4 @@ glyph-block Letter-Latin-Lower-T : begin
xLeft + (BBD / 2) + LongJut + TBalance2
begin yCrossBar
begin BBS
Rect Ascender 0 xLeft (xLeft + BBD)
Rect Ascender 0 xLeft (xLeft + BBD)

View file

@ -1,6 +1,6 @@
$$include '../../../meta/macros.ptl'
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
import [mix fallback SuffixCfg] from"../../../support/utils.mjs"
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
glyph-module
@ -323,43 +323,32 @@ glyph-block Letter-Latin-W : begin
define [WCursiveImpl df top bodyType serifsType] : WCursiveImplImpl false df top bodyType serifsType
define [WHookTopCursive df top bodyType serifsType] : WCursiveImplImpl true df top bodyType serifsType
define WConfig : object
cyrlCapialOmega { WShapeImpl WHooktopShape FORM-CYRL-OMEGA SERIFS-CYRL-OMEGA }
cyrlSmallOmega { WShapeImpl WHooktopShape FORM-CYRL-OMEGA SERIFS-CURSIVE }
define WConfig : SuffixCfg.weave
# Body
object
straight { WShapeImpl WHooktopShape FORM-STRAIGHT }
straightAsymmetric { WShapeImpl WHooktopShape FORM-ASYMMETRIC }
straightDoubleV { WShapeImpl WHooktopShape FORM-DOUBLE-V }
straightFlatTop { WShapeImpl WHooktopShape FORM-FLAT-TOP }
straightVerticalSides { WVertSides WVSHookTopShape FORM-STRAIGHT }
curly { WShapeImpl WHooktopShape FORM-CURLY }
cursive { WCursiveImpl WHookTopCursive FORM-CURLY }
cyrlCapialOmega { WShapeImpl WHooktopShape FORM-CYRL-OMEGA }
cyrlSmallOmega { WShapeImpl WHooktopShape FORM-CYRL-OMEGA }
straightAsymmetric { WShapeImpl WHooktopShape FORM-ASYMMETRIC SERIFS-ASYMMETRIC }
straightDoubleV { WShapeImpl WHooktopShape FORM-DOUBLE-V SERIFS-DOUBLE-V }
straightFlatTop { WShapeImpl WHooktopShape FORM-FLAT-TOP SERIFS-AUTO }
straight { WShapeImpl WHooktopShape FORM-STRAIGHT SERIFS-AUTO }
straightVerticalSides { WVertSides WVSHookTopShape FORM-STRAIGHT SERIFS-AUTO }
curly { WShapeImpl WHooktopShape FORM-CURLY SERIFS-AUTO }
cursive { WCursiveImpl WHookTopCursive FORM-CURLY SERIFS-CURSIVE }
# Serifs
function [body] : if (body == 'cyrlCapialOmega' || body == 'cyrlSmallOmega')
then : object ["" SERIFS-CYRL-OMEGA]
else : object
serifless SERIFS-NONE
motionSerifed SERIFS-MOTION
serifed : match body
[Just 'straightAsymmetric'] SERIFS-ASYMMETRIC-ALL
[Just 'straightDoubleV'] SERIFS-DOUBLE-V-ALL
[Just 'cursive'] SERIFS-MOTION
__ SERIFS-ALL
straightAsymmetricSerifless { WShapeImpl WHooktopShape FORM-ASYMMETRIC SERIFS-NONE }
straightDoubleVSerifless { WShapeImpl WHooktopShape FORM-DOUBLE-V SERIFS-NONE }
straightFlatTopSerifless { WShapeImpl WHooktopShape FORM-FLAT-TOP SERIFS-NONE }
straightVerticalSidesSerifless { WVertSides WVSHookTopShape FORM-STRAIGHT SERIFS-NONE }
straightSerifless { WShapeImpl WHooktopShape FORM-STRAIGHT SERIFS-NONE }
curlySerifless { WShapeImpl WHooktopShape FORM-CURLY SERIFS-NONE }
cursiveSerifless { WCursiveImpl WHookTopCursive FORM-CURLY SERIFS-NONE }
straightAsymmetricMotionSerifed { WShapeImpl WHooktopShape FORM-ASYMMETRIC SERIFS-MOTION }
straightDoubleVMotionSerifed { WShapeImpl WHooktopShape FORM-DOUBLE-V SERIFS-MOTION }
straightFlatTopMotionSerifed { WShapeImpl WHooktopShape FORM-FLAT-TOP SERIFS-MOTION }
straightVerticalSidesMotionSerifed { WVertSides WVSHookTopShape FORM-STRAIGHT SERIFS-MOTION }
straightMotionSerifed { WShapeImpl WHooktopShape FORM-STRAIGHT SERIFS-MOTION }
curlyMotionSerifed { WShapeImpl WHooktopShape FORM-CURLY SERIFS-MOTION }
cursiveMotionSerifed { WCursiveImpl WHookTopCursive FORM-CURLY SERIFS-MOTION }
straightAsymmetricSerifed { WShapeImpl WHooktopShape FORM-ASYMMETRIC SERIFS-ASYMMETRIC-ALL }
straightDoubleVSerifed { WShapeImpl WHooktopShape FORM-DOUBLE-V SERIFS-DOUBLE-V-ALL }
straightFlatTopSerifed { WShapeImpl WHooktopShape FORM-FLAT-TOP SERIFS-ALL }
straightVerticalSidesSerifed { WVertSides WVSHookTopShape FORM-STRAIGHT SERIFS-ALL }
straightSerifed { WShapeImpl WHooktopShape FORM-STRAIGHT SERIFS-ALL }
curlySerifed { WShapeImpl WHooktopShape FORM-CURLY SERIFS-ALL }
cursiveSerifed { WCursiveImpl WHookTopCursive FORM-CURLY SERIFS-MOTION }
foreach { suffix { implT hookTopImplT bodyType slabType } } [Object.entries WConfig] : do
foreach { suffix { {implT hookTopImplT bodyType} slabType } } [pairs-of WConfig] : do
create-glyph "W.\(suffix)" : glyph-proc
local df : DivFrame para.diversityM 3
set-width df.width

View file

@ -1,6 +1,6 @@
$$include '../../meta/macros.ptl'
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [mix clamp fallback SuffixCfg] from"../../support/utils.mjs"
import [AnyCv getGrMesh VS01] from"../../support/gr.mjs"
glyph-module
@ -105,8 +105,8 @@ glyph-block Digits-Zero : begin
define [BrokenVerticalBar top] : difference
VBar.m Middle (0 + O) (top - O) [Math.min (CircleInnerWidth * 0.375) OverlayStroke]
intersection
MaskAbove (top * (1/2 + 1/16))
MaskBelow (top * (1/2 - 1/16))
MaskAbove (top * (1/2 - 1/16))
MaskBelow (top * (1/2 + 1/16))
define [ZeroDotShape top] : begin
local halfDotWidth : Math.min DotRadius (CircleInnerWidth / 4)
@ -150,50 +150,48 @@ glyph-block Digits-Zero : begin
Middle + halfDotWidth - OX
begin 0
define ZeroConfig : object
'unslashed' { null null }
'slashed' { ZeroSlash null }
'reverseSlashed' { ZeroRevSlash null }
'tallSlashed' { ZeroTallSlash null }
'tallReverseSlashed' { ZeroTallRevSlash null }
'dotted' { ZeroDotShape null }
'longDotted' { ZeroLongDotShape null }
'slashedSplit' { ZeroSlash InsetShape }
'reverseSlashedSplit' { ZeroRevSlash InsetShape }
'brokenSlash' { BrokenTallSlash null }
'brokenReverseSlash' { BrokenTallRevSlash null }
'brokenVerticalBar' { BrokenVerticalBar null }
'slashedCutout' { CutoutSlash Cutout }
'reverseSlashedCutout' { CutoutRevSlash Cutout }
'tallSlashedCutout' { CutoutTallSlash Cutout }
'tallReverseSlashedCutout' { CutoutTallRevSlash Cutout }
'verticalBarCutout' { CutoutVerticalBar Cutout }
'topRightCutout' { TopRightCutoutSlash Cutout }
define ZeroConfig : SuffixCfg.weave
object # outline shape
'' { ZeroOutlineShape ZeroOutlineMask }
'oval' { ZeroOvalShape ZeroOvalMask }
object # overlay/cutout
'unslashed' { null null }
'slashed' { ZeroSlash null }
'reverseSlashed' { ZeroRevSlash null }
'tallSlashed' { ZeroTallSlash null }
'tallReverseSlashed' { ZeroTallRevSlash null }
'dotted' { ZeroDotShape null }
'longDotted' { ZeroLongDotShape null }
'slashedSplit' { ZeroSlash InsetShape }
'reverseSlashedSplit' { ZeroRevSlash InsetShape }
'brokenSlash' { BrokenTallSlash null }
'brokenReverseSlash' { BrokenTallRevSlash null }
'brokenVerticalBar' { BrokenVerticalBar null }
'slashedCutout' { CutoutSlash Cutout }
'reverseSlashedCutout' { CutoutRevSlash Cutout }
'tallSlashedCutout' { CutoutTallSlash Cutout }
'tallReverseSlashedCutout' { CutoutTallRevSlash Cutout }
'verticalBarCutout' { CutoutVerticalBar Cutout }
'topRightCutout' { TopRightCutoutSlash Cutout }
define Shapes : object
'' { ZeroOutlineShape ZeroOutlineMask }
'Oval' { ZeroOvalShape ZeroOvalMask }
define Infixes : object
define Heights : object
'lnum' { CAP [function [] : MarkSet.capital] }
'onum' { OnumHeight [function [] : OnumMarks.e] }
foreach { shapeSuffix { Outline Mask } } [Object.entries Shapes] : begin
foreach { infix { height Marks } } [Object.entries Infixes] : begin
local zeroShape : Outline height
foreach { suffix { Overlay Postproc } } [Object.entries ZeroConfig] : begin
create-glyph "zero.\(infix).\(suffix)\(shapeSuffix)" : glyph-proc
include : Marks
local overlayShape : if Overlay [Overlay height] null
if Postproc
: then : begin
include : Postproc zeroShape overlayShape Mask height
: else : begin
include zeroShape
if Overlay : if Mask
include : intersection overlayShape : Mask height
include overlayShape
foreach { suffix { {Outline Mask} {Overlay Postproc} } } [pairs-of ZeroConfig] : begin
foreach { infix { height Marks } } [pairs-of Heights] : begin
create-glyph "zero.\(infix).\(suffix)" : glyph-proc
include : Marks
local zeroShape : Outline height
local overlayShape : if Overlay [Overlay height] null
if Postproc
: then : begin
include : Postproc zeroShape overlayShape Mask height
: else : begin
include zeroShape
if Overlay : if Mask
include : intersection overlayShape : Mask height
include overlayShape
select-variant 'zero.lnum' [CodeLnum '0'] (follow -- 'zero')
select-variant 'zero.onum' [CodeOnum '0'] (follow -- 'zero')

View file

@ -1,6 +1,11 @@
### Autoarg macro
define-operator "--" 890 'right' : syntax-rules
`(@l -- @r) [atom l] : dirty `[new $NamedParameterPair$ @{".quote" [formOf l]} @r]
`(@{".quote" l} -- @r) : dirty `[new $NamedParameterPair$ @l @r]
### Arbitrary pair operator
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
### Macro for identity match
define-macro Just : begin
@ -30,7 +35,7 @@ define-macro params : syntax-rules
local declarations `[begin]
local namedAssigns `[begin]
local indexAssigns `[begin]
local tearDowns `[begin]
local tearDowns `[begin]
local j 0
foreach [pf : items-of : formOf _pairs] : begin
@ -204,14 +209,13 @@ define-macro glyph-block : syntax-rules
([typeof form] === "string") : set variableSet.(form) true
traceBody body
traceBody `[$NamedParameterPair$ $DoNothing$ $createAndSaveGlyphImpl$ $assignUnicodeImpl$]
traceBody `[$NamedParameterPair$ $createAndSaveGlyphImpl$ $assignUnicodeImpl$ $execState$]
set externEnv.$glyphBlockVariableUsage$ variableSet
define captureImports `[$createAndSaveGlyphImpl$ $NamedParameterPair$
$assignUnicodeImpl$ $DoNothing$ $execState$
Metrics para recursive glyphStore glyph-is-needed SpiroFns BooleFns MarkSet AS_BASE
ALSO_METRICS buildGlyphs tagged DivFrame fontMetrics]
define captureImports `[$createAndSaveGlyphImpl$ $NamedParameterPair$ $assignUnicodeImpl$
$execState$ Metrics para recursive glyphStore glyph-is-needed SpiroFns BooleFns
MarkSet AS_BASE ALSO_METRICS buildGlyphs tagged DivFrame fontMetrics]
define metricImports `[DesignParameters UPM HalfUPM Width SB CAP XH Ascender Descender
Contrast SymbolMid ParenTop ParenBot OperTop OperBot TackTop TackBot PlusTop PlusBot

View file

@ -1,12 +1,11 @@
$$include '../meta/macros.ptl'
import [AddCommonFeature AddFeature AddLookup AddFeatureLookup ChainRuleBuilder BeginLookupBlock EndLookupBlock UkMapToLookup UkMap2ToLookup] from"./table-util.mjs"
import [AnyCv Dotless TieMark TieGlyph OgonekTrY IsSuperscript IsSubscript] from"../support/gr.mjs"
import as UnicodeKnowledge from"../meta/unicode-knowledge.mjs"
extern Set
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
define-macro Ccmp-Group : syntax-rules
`[Ccmp-Group @description @body]
dirty `[$ExecCcmpGroup$ [function [export-lookup chain-rule] @[formOf body]]]

View file

@ -1,3 +1,5 @@
$$include '../meta/macros.ptl'
import [AddLookup AddCommonFeature PickCommonFeature AddFeatureLookup PickLookup BeginLookupBlock EndLookupBlock ChainRuleBuilder] from"./table-util.mjs"
import [Cv AnyCv CvDecompose RightDependentLink RightDependentTrigger] from"../support/gr.mjs"
@ -5,8 +7,6 @@ extern Map
extern Set
define look-around null
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
define [FeatureName tag] : tag + '_cvss'
define [SsLookupName tag] : 'lookup_ss_' + tag

View file

@ -1,9 +1,8 @@
$$include '../meta/macros.ptl'
import [AddCommonFeature AddFeature AddLookup BeginLookupBlock EndLookupBlock ChainRuleBuilder] from"./table-util.mjs"
import [NumeratorForm DenominatorForm] from"../support/gr.mjs"
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
# Name-driven feature pairs
export : define [buildFrac sink glyphStore] : begin
local rec : BeginLookupBlock sink

View file

@ -1,10 +1,9 @@
$$include '../meta/macros.ptl'
import [AddCommonFeature AddFeature ChainRuleBuilder BeginLookupBlock EndLookupBlock] from"./table-util.mjs"
extern Map
extern Set
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
define [arrowBarX s] : lambda [t] : t.map : lambda [x] "\(x).arrowBar.\(s)"
define [lsx s] : lambda [t] : t.map : lambda [x] "\(x).lig.\(s)"
define [csx s] : lambda [t] : t.map : lambda [x] "\(x).\(s)"

View file

@ -1,7 +1,6 @@
import [AddCommonFeature AddFeature AddLookup ChainRuleBuilder QueryRelatedGlyphs BeginLookupBlock EndLookupBlock] from"./table-util.mjs"
$$include '../meta/macros.ptl'
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
import [AddCommonFeature AddFeature AddLookup ChainRuleBuilder QueryRelatedGlyphs BeginLookupBlock EndLookupBlock] from"./table-util.mjs"
export : define [buildGsubThousands sink para] : begin
local rec : BeginLookupBlock sink

View file

@ -34,28 +34,49 @@ export function joinCamel(a, b) {
return a + b[0].toUpperCase() + b.slice(1);
}
function joinSuffixListImpl(sink, k, v, configs) {
function joinSuffixListImpl(sink, k, v, telescope, configs) {
if (!configs.length) {
sink[k] = v;
return;
}
for (const [keySuffix, valueSuffix] of Object.entries(configs[0])) {
let [item, ...rest] = configs;
if (item instanceof Function) item = item(...telescope);
if (!item) return;
for (const [keySuffix, valueSuffix] of Object.entries(item)) {
const k1 = joinCamel(k, keySuffix);
const v1 = [...v, valueSuffix];
joinSuffixListImpl(sink, k1, v1, configs.slice(1));
const telescope1 = [...telescope, keySuffix];
joinSuffixListImpl(sink, k1, v1, telescope1, rest);
}
}
export const SuffixCfg = {
weave: function (...configs) {
let ans = {};
joinSuffixListImpl(ans, "", [], configs);
joinSuffixListImpl(ans, "", [], [], configs);
return ans;
},
combine: function (...configs) {
let ans = {};
for (const item of configs) for (const [k, v] of Object.entries(item)) ans[k] = v;
return ans;
},
collect: function (pairs) {
let ans = {};
for (const pair of pairs) {
if (pair) ans[pair.left] = pair.right;
}
return ans;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
export class $NamedParameterPair$ {
constructor(l, r) {
this.left = l;
this.right = r;
}
}

View file

@ -261,55 +261,36 @@ class VbStageAlternative {
this.key = key;
this.rank = raw.rank;
this.next = raw.next;
if (key !== "*") this.keySuffix = raw.keySuffix ?? key;
this.descriptionSuffix = raw.descriptionSuffix;
this.descriptionJoiner = raw.descriptionJoiner || "with";
this.mode = raw.mode;
this.disableIf = raw.disableIf;
this.selectorSuffix = raw.selectorSuffix;
if (key !== "*") this.keyAffix = raw.keyAffix ?? key;
this.descriptionAffix = raw.descriptionAffix;
this.descriptionJoiner = raw.descriptionJoiner || "with";
this.selectorAffix = raw.selectorAffix;
}
fallback(defaultAlternative) {
this.next = this.next || defaultAlternative.next;
this.keySuffix = this.keySuffix || defaultAlternative.keySuffix;
this.descriptionSuffix = this.descriptionSuffix || defaultAlternative.descriptionSuffix;
this.mode = this.mode || defaultAlternative.mode || "append";
this.keyAffix = this.keyAffix || defaultAlternative.keyAffix;
this.descriptionAffix = this.descriptionAffix || defaultAlternative.descriptionAffix;
this.descriptionJoiner = this.descriptionJoiner || defaultAlternative.descriptionJoiner;
this.disableIf = this.disableIf || defaultAlternative.disableIf;
this.selectorSuffix = this.selectorSuffix || defaultAlternative.selectorSuffix;
}
tryAccept(globalState, localState) {
// Detect whether this alternative is applicable.
if (this.disableIf) {
for (const branch of this.disableIf) {
let statementMatches = true;
for (let [k, v] of Object.entries(branch)) {
v = v.trim();
if (/^NOT(?=\s)/.test(v)) {
v = v.slice(3).trim();
if (localState.assignments.get(k) === v) {
statementMatches = false;
break;
}
} else {
if (localState.assignments.get(k) !== v) {
statementMatches = false;
break;
}
}
}
if (statementMatches) return null;
}
}
// Reject if disable conditions match
if (this.shouldReject(localState)) return null;
// Accept this alternative.
const ans = localState.clone();
ans.stage = this.next;
ans.assignments.set(this.stage, this.key);
if (this.keySuffix) ans.key.push(this.keySuffix);
if (this.descriptionJoiner && this.descriptionSuffix)
ans.addDescription(this.descriptionJoiner, this.descriptionSuffix);
if (this.selectorSuffix)
for (const [selector, suffix] of Object.entries(this.selectorSuffix))
ans.addSelector(selector, suffix);
if (this.keyAffix) ans.addKeyAffix(this.mode, this.keyAffix);
if (this.descriptionJoiner && this.descriptionAffix)
ans.addDescription(this.mode, this.descriptionJoiner, this.descriptionAffix);
if (this.selectorAffix)
for (const [selector, suffix] of Object.entries(this.selectorAffix))
ans.addSelectorAffix(this.mode, selector, suffix);
if (!this.next) {
ans.rank = ++globalState.rank;
@ -319,6 +300,31 @@ class VbStageAlternative {
return ans;
}
}
shouldReject(localState) {
if (!this.disableIf) return false;
for (const branch of this.disableIf) {
let statementMatches = true;
for (let [k, v] of Object.entries(branch)) {
v = v.trim();
if (/^NOT(?=\s)/.test(v)) {
v = v.slice(3).trim();
if (localState.assignments.get(k) === v) {
statementMatches = false;
break;
}
} else {
if (localState.assignments.get(k) !== v) {
statementMatches = false;
break;
}
}
}
if (statementMatches) return true;
}
return false;
}
}
class VbGlobalState {
@ -354,13 +360,56 @@ class VbLocalState {
return ans;
}
addDescription(joiner, segment) {
addKeyAffix(mode, segment) {
switch (mode) {
case "append":
this.key.push(segment);
return;
case "prepend":
this.key.unshift(segment);
return;
case "replace":
this.key = [segment];
return;
default:
throw new Error(`Invalid key affix mode: ${mode}`);
}
}
addDescription(mode, joiner, segment) {
if (!segment) return;
if (!this.descriptions.has(joiner)) this.descriptions.set(joiner, []);
this.descriptions.get(joiner).push(segment);
let descriptionSentence = this.descriptions.get(joiner);
switch (mode) {
case "append":
descriptionSentence.push(segment);
return;
case "prepend":
descriptionSentence.unshift(segment);
return;
case "replace":
descriptionSentence.length = 0;
descriptionSentence.push(segment);
return;
default:
throw new Error(`Invalid description affix mode: ${mode}`);
}
}
addSelector(selector, value) {
this.selector.set(selector, joinCamel(this.selector.get(selector), value));
addSelectorAffix(mode, selector, value) {
switch (mode) {
case "append":
this.selector.set(selector, joinCamel(this.selector.get(selector), value));
return;
case "prepend":
this.selector.set(selector, joinCamel(value, this.selector.get(selector)));
return;
case "replace":
this.selector.set(selector, value);
return;
default:
throw new Error(`Invalid selector affix mode: ${mode}`);
}
}
produceKey() {
@ -388,5 +437,5 @@ class VbLocalState {
function arrayToSentence(arr) {
if (arr.length == 1) return arr[0];
let last = arr.pop();
return arr.join(", ") + " and " + last;
return arr.join(", ") + ", and " + last;
}

File diff suppressed because it is too large Load diff