238 lines
9.6 KiB
Text
238 lines
9.6 KiB
Text
import [add-common-feature add-feature add-lookup add-feature-lookup ChainRuleBuilder BeginLookupBlock EndLookupBlock UkMapToLookup UkMap2ToLookup] from "./table-util"
|
|
import [AnyCv Dotless TieMark TieGlyph CcmpDecompose] from "../support/gr"
|
|
import as UnicodeKnowledge from "../meta/unicode-knowledge"
|
|
|
|
extern Set
|
|
|
|
define-operator "~>" 880 'right' : syntax-rules
|
|
`(@l ~> @r) `{.left @l .right @r}
|
|
|
|
export : define [buildCCMP sink glyphStore markGlyphs] : begin
|
|
local rec : BeginLookupBlock sink
|
|
|
|
define ccmp : add-feature sink 'ccmp'
|
|
define {chain-rule} : ChainRuleBuilder sink
|
|
|
|
define groupGrekUpperTonos {}
|
|
define groupTR {}
|
|
define groupLF {}
|
|
define dotlessFrom {}
|
|
define dotlessTo {}
|
|
define TieMarkFrom {}
|
|
define TieMarkTo {}
|
|
define TieGlyphs {}
|
|
|
|
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== "."): begin
|
|
if g.baseAnchors.trailing : groupTR.push gid
|
|
if g.baseAnchors.lf : groupLF.push gid
|
|
if g.baseAnchors.grekUpperTonos : groupGrekUpperTonos.push gid
|
|
if [Dotless.get g] : begin
|
|
dotlessFrom.push gid
|
|
dotlessTo.push [Dotless.get g]
|
|
if [TieGlyph.get g] : TieGlyphs.push gid
|
|
if [TieMark.get g] : begin
|
|
TieMarkFrom.push gid
|
|
TieMarkTo.push [TieMark.get g]
|
|
|
|
define [IotaLF] : UkMapToLookup UnicodeKnowledge.iotaBelowToLfTf
|
|
define [OgonekTrailing] : UkMapToLookup UnicodeKnowledge.ogonekBelowToTRTf
|
|
define [GrekUpperTonosTf] : UkMapToLookup UnicodeKnowledge.upperGrekMarkToTonosTf
|
|
|
|
define [ToneToToneStart toneEnd] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneStart [range 4 downtill 0] : begin
|
|
f.push ('tone' + toneStart)
|
|
e.push ('toneStart' + toneStart + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define [ToneToToneEnd toneStart] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('tone' + toneEnd)
|
|
e.push ('toneEnd' + toneStart + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define [ToneStartOrMidAt y]: begin
|
|
local f {}
|
|
foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneStart' + y + toneEnd)
|
|
foreach toneStart [range 4 downtill 0] : foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneMid' + toneStart + y + toneEnd)
|
|
return f
|
|
|
|
define [ToneStartToToneMid toneStart] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneMid [range 4 downtill 0] : foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneStart' + toneMid + toneEnd)
|
|
e.push ('toneMid' + toneStart + toneMid + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define [ToneSandhiToToneStart toneEnd] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneStart [range 4 downtill 0] : begin
|
|
f.push ('toneSandhi' + toneStart)
|
|
e.push ('toneSandhiStart' + toneStart + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define [ToneSandhiToToneEnd toneStart] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneSandhi' + toneEnd)
|
|
e.push ('toneSandhiEnd' + toneStart + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define [ToneSandhiStartOrMidAt y]: begin
|
|
local f {}
|
|
foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneSandhiStart' + y + toneEnd)
|
|
foreach toneStart [range 4 downtill 0] : foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneSandhiMid' + toneStart + y + toneEnd)
|
|
return f
|
|
|
|
define [ToneSandhiStartToToneMid toneStart] : begin
|
|
local f {}
|
|
local e {}
|
|
foreach toneMid [range 4 downtill 0] : foreach toneEnd [range 4 downtill 0] : begin
|
|
f.push ('toneSandhiStart' + toneMid + toneEnd)
|
|
e.push ('toneSandhiMid' + toneStart + toneMid + toneEnd)
|
|
return (f ~> e)
|
|
|
|
define lookupMarks1 : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
# Dot removal (max 6 middle marks are supported)
|
|
chain-rule (dotlessFrom ~> dotlessTo) (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all markGlyphs.all (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all markGlyphs.all markGlyphs.all (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all (markGlyphs.above ~> null)
|
|
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all (markGlyphs.above ~> null)
|
|
|
|
# Iota transform (max 6 middle marks are supported)
|
|
chain-rule groupLF [IotaLF]
|
|
chain-rule groupLF markGlyphs.all [IotaLF]
|
|
chain-rule groupLF markGlyphs.all markGlyphs.all [IotaLF]
|
|
chain-rule groupLF markGlyphs.all markGlyphs.all markGlyphs.all [IotaLF]
|
|
chain-rule groupLF markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [IotaLF]
|
|
chain-rule groupLF markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [IotaLF]
|
|
chain-rule groupLF markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [IotaLF]
|
|
|
|
# Ogonek transform (max 6 middle marks are supported)
|
|
chain-rule groupTR [OgonekTrailing]
|
|
chain-rule groupTR markGlyphs.all [OgonekTrailing]
|
|
chain-rule groupTR markGlyphs.all markGlyphs.all [OgonekTrailing]
|
|
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
|
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
|
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
|
|
|
define lookupMarks2 : add-lookup sink : object
|
|
.type 'gsub_ligature'
|
|
.substitutions : UkMap2ToLookup UnicodeKnowledge.markCompositionTf
|
|
|
|
define lookupMarks3 : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule groupGrekUpperTonos [GrekUpperTonosTf]
|
|
|
|
define lookupCcmp-TieMarkLigature : add-lookup sink : object
|
|
.type 'gsub_ligature'
|
|
.substitutions : {}.concat
|
|
TieMarkFrom.map : lambda [gnFrom idx]
|
|
object [from {'cgj' gnFrom}] [to TieMarkTo.(idx)]
|
|
|
|
define lookupTieMarkContextual : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list : object
|
|
match {[TieGlyphs.concat TieMarkTo] {'cgj'} TieMarkFrom}
|
|
inputBegins 1
|
|
inputEnds 3
|
|
apply {{.at 1 .lookup lookupCcmp-TieMarkLigature}}
|
|
|
|
define lookupToneStart : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneToToneStart 0] {'tone0'}
|
|
chain-rule [ToneToToneStart 1] {'tone1'}
|
|
chain-rule [ToneToToneStart 2] {'tone2'}
|
|
chain-rule [ToneToToneStart 3] {'tone3'}
|
|
chain-rule [ToneToToneStart 4] {'tone4'}
|
|
|
|
define lookupToneMid : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneStartOrMidAt 0] [ToneStartToToneMid 0]
|
|
chain-rule [ToneStartOrMidAt 1] [ToneStartToToneMid 1]
|
|
chain-rule [ToneStartOrMidAt 2] [ToneStartToToneMid 2]
|
|
chain-rule [ToneStartOrMidAt 3] [ToneStartToToneMid 3]
|
|
chain-rule [ToneStartOrMidAt 4] [ToneStartToToneMid 4]
|
|
|
|
define lookupToneEnd : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneStartOrMidAt 0] [ToneToToneEnd 0]
|
|
chain-rule [ToneStartOrMidAt 1] [ToneToToneEnd 1]
|
|
chain-rule [ToneStartOrMidAt 2] [ToneToToneEnd 2]
|
|
chain-rule [ToneStartOrMidAt 3] [ToneToToneEnd 3]
|
|
chain-rule [ToneStartOrMidAt 4] [ToneToToneEnd 4]
|
|
|
|
define lookupToneSandhiStart : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneSandhiToToneStart 0] {'toneSandhi0'}
|
|
chain-rule [ToneSandhiToToneStart 1] {'toneSandhi1'}
|
|
chain-rule [ToneSandhiToToneStart 2] {'toneSandhi2'}
|
|
chain-rule [ToneSandhiToToneStart 3] {'toneSandhi3'}
|
|
chain-rule [ToneSandhiToToneStart 4] {'toneSandhi4'}
|
|
|
|
define lookupToneSandhiMid : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneSandhiStartOrMidAt 0] [ToneSandhiStartToToneMid 0]
|
|
chain-rule [ToneSandhiStartOrMidAt 1] [ToneSandhiStartToToneMid 1]
|
|
chain-rule [ToneSandhiStartOrMidAt 2] [ToneSandhiStartToToneMid 2]
|
|
chain-rule [ToneSandhiStartOrMidAt 3] [ToneSandhiStartToToneMid 3]
|
|
chain-rule [ToneSandhiStartOrMidAt 4] [ToneSandhiStartToToneMid 4]
|
|
|
|
define lookupToneSandhiEnd : add-lookup sink : object
|
|
.type 'gsub_chaining'
|
|
.rules : list
|
|
chain-rule [ToneSandhiStartOrMidAt 0] [ToneSandhiToToneEnd 0]
|
|
chain-rule [ToneSandhiStartOrMidAt 1] [ToneSandhiToToneEnd 1]
|
|
chain-rule [ToneSandhiStartOrMidAt 2] [ToneSandhiToToneEnd 2]
|
|
chain-rule [ToneSandhiStartOrMidAt 3] [ToneSandhiToToneEnd 3]
|
|
chain-rule [ToneSandhiStartOrMidAt 4] [ToneSandhiToToneEnd 4]
|
|
|
|
|
|
ccmp.lookups.push lookupMarks1 lookupMarks2 lookupMarks3 lookupTieMarkContextual
|
|
sink.lookupDep.push {lookupMarks1 lookupMarks2}
|
|
sink.lookupDep.push {lookupMarks2 lookupMarks3}
|
|
sink.lookupDep.push {lookupMarks3 lookupTieMarkContextual}
|
|
ccmp.lookups.push lookupToneStart lookupToneMid lookupToneEnd
|
|
sink.lookupDep.push {lookupToneStart lookupToneMid}
|
|
sink.lookupDep.push {lookupToneMid lookupToneEnd}
|
|
ccmp.lookups.push lookupToneSandhiStart lookupToneSandhiMid lookupToneSandhiEnd
|
|
sink.lookupDep.push {lookupToneSandhiStart lookupToneSandhiMid}
|
|
sink.lookupDep.push {lookupToneSandhiMid lookupToneSandhiEnd}
|
|
|
|
# CCMP decomposition
|
|
define decompositions {.}
|
|
foreach { gid g } [glyphStore.namedEntries] : begin
|
|
local parts : CcmpDecompose.get g
|
|
if (parts && parts.length) : set decompositions.(gid) parts
|
|
|
|
if [objectIsNotEmpty decompositions] : begin
|
|
define lookupCcmp-Decompose : add-lookup sink : object
|
|
.type 'gsub_multiple'
|
|
.substitutions decompositions
|
|
add-feature-lookup ccmp lookupCcmp-Decompose
|
|
|
|
add-common-feature sink ccmp
|
|
EndLookupBlock rec sink
|
|
|
|
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length
|