import 'unorm' as unorm

import './support/glyph' as Glyph
import './support/point' as Point
import './support/spirokit' as spirokit
import './support/transform' as : Transform && [object [transformPoint tp] [untransform utp] inverse]
import './support/anchor' as Anchor
import './support/monotonic-interpolate' as smoothreg
import './support/fairify' as fairify

extern global
define [suggestGC] : begin
	if (global && global.gc) : global.gc
	return nothing

### File inclusion macro
define-macro $$include : syntax-rules
	{'$$include' {'.quote' file}} : begin
		local path : require 'path'
		local fs : require 'fs'
		local f0 [[env.macros.get 'input-path']].1
		local parse [require './syntax.js'].parse
		
		local absolutePath : path.resolve [path.dirname f0] [formOf file]
		local input : fs.readFileSync absolutePath 'utf-8'
		local ast : parse input {.within {.file absolutePath .input input}}
		return {'.syntactic-closure' ast env}
	otherwise `nothing

### Autoarg macro
define [$NamedParameterPair$ l r] : begin
	set this.left l
	set this.right r
	return this

define-operator "--" 890 'right' : syntax-rules
	`(@l -- @r) [atom l] `[new $NamedParameterPair$ @{".quote" [formOf l]} @r]

define-macro params : syntax-rules
	`[params @_pairs @body] : begin
		local ta : env.newt
		local tb : env.newt
		local t : env.newt
		local ps `[begin
			[local @ta : {}.slice.call arguments 0]
			[local @tb {}]
			[for [local @t 0] (@t < @ta.length) [inc @t] : if [not : @ta.(@t) <@ $NamedParameterPair$] : @tb.push @ta.(@t)]
		]
		local aps `[begin]
		local dps `[begin]
		local j 0
		foreach [pf : items-of : formOf _pairs] : begin
			local name
			if [atom pf] : then
				ps.push `[local @pf : fallback @pf (@tb).(@{".quote" j})]
				set name pf
			: else
				ps.push `[local @(pf.0) : fallback @(pf.0) (@tb).(@{".quote" j}) @(pf.1)]
				set name pf.0
			aps.push `[if (@t && @t <@ $NamedParameterPair$ && @t.left == @{".quote" name}) [set @name @t.right]]
			if pf.2 : dps.push `[local @(pf.2) @name]
			inc j
		ps.push `[foreach [@t : items-of @ta] @aps]
		ps.push dps
		ps.push : formOf body
		return : dirty ps

### Point macro
define-operator "<>" 800 "never" : begin
	local tClass [definingEnv.newt 'class']
	local m : syntax-rules
		`(@x <> @y) `[new @tClass @x @y]

	set coinit.initFn : lambda [m] : begin
		set m.toPattern : lambda [form env wrapper] : match form
			`(@x <> @y) : begin
				local p1 [toPattern x env wrapper]
				local p2 [toPattern y env wrapper]
				object
					whether : lambda [t] `(@t && @[p1.whether `(@t.x)] && @[p2.whether `(@t.y)])
					assign : lambda [t locallyQ] : ex `[begin 
						@{".preserve" [p1.assign `(@t.x) locallyQ]}
						@{".preserve" [p2.assign `(@t.y) locallyQ]}
					] env

	set coinit.injectForm `[define [@tClass x y] : begin \\
		set this.x x
		set this.y y
		return nothing
	]
	return m

# A symbol block defines a group of similar glyphs. They may expose some functions used in glyphs in other blocks.
define-macro symbol-block : syntax-rules
	`[symbol-block @name @::steps] : let [t : env.newt] : dirty `[begin [let : set @t : begin @::[steps.map formOf]] [progress @name] @t]

### Necessary macros
# A glyph construction is a function which "modifies" a glyph.
define-macro glyph-construction : syntax-rules
	`[glyph-construction @::steps] {'.syntactic-closure' `[lambda [] [begin \\
		local currentGlyph this
		begin @::[steps.map formOf]
		return nothing
	]] env}
# Remap Glyph's methods to macros in order to simplify writing
define-macro set-width : syntax-rules
	`[set-width @::args] {'.syntactic-closure' `[currentGlyph.set-width @::args] env}
define-macro start-from : syntax-rules
	`[start-from @::args] {'.syntactic-closure' `[currentGlyph.start-from @::args] env}
define-macro line-to : syntax-rules
	`[line-to @::args] {'.syntactic-closure' `[currentGlyph.line-to @::args] env}
define-macro curve-to : syntax-rules
	`[curve-to @::args] {'.syntactic-closure' `[currentGlyph.curve-to @::args] env}
define-macro cubic-to : syntax-rules
	`[cubic-to @::args] {'.syntactic-closure' `[currentGlyph.cubic-to @::args] env}
define-macro include : syntax-rules
	`[include glyphs.(@name) @::args] : dirty `[includeGlyphPart currentGlyph glyphs @name @::args]
	`[include @::args] {'.syntactic-closure' `[currentGlyph.include @::args] env}
define-macro set-anchor : syntax-rules
	`[set-anchor @::args] {'.syntactic-closure' `[currentGlyph.set-anchor @::args] env}
define-macro apply-transform : syntax-rules
	`[apply-transform @::args] {'.syntactic-closure' `[currentGlyph.apply-transform @::args] env}
define-macro reverse-last : syntax-rules
	`[reverse-last @::args] {'.syntactic-closure' `[currentGlyph.reverse-last @::args] env}
define-macro depends-on : syntax-rules
	`[depends-on @::args] {'.syntactic-closure' `[currentGlyph.depends-on @::args] env}
define-macro eject-contour : syntax-rules
	`[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.eject-contour @::args] env}
define-macro tag-contour : syntax-rules
	`[tag-contour @::args] {'.syntactic-closure' `[currentGlyph.tag-contour @::args] env}
define-macro retag-contour : syntax-rules
	`[retag-contour @::args] {'.syntactic-closure' `[currentGlyph.retag-contour @::args] env}
define-macro assign-unicode : syntax-rules
	`[assign-unicode @code] {".syntactic-closure" `[begin \\
		currentGlyph.assign-unicode @code
		set unicodeGlyphs.(currentGlyph.unicode.((currentGlyph.unicode.length - 1))) currentGlyph
	] env}

define [includeGlyphPart cg gs nm] : begin
	if [not gs.(nm)] : throw : new Error "Glyph \(nm) is not defined, which is used for \(cg.name)."
	return : cg.include.apply cg [{gs.(nm)}.concat [{}.slice.call arguments 3]]

###### Canvas-based mechanism
define [$donothing$] nothing
define-macro sketch : syntax-rules
	`[sketch @::steps] : begin
		if [not externEnv.$nWFGlyphs$] : set externEnv.$nWFGlyphs$ 0
		inc externEnv.$nWFGlyphs$
		dirty `[[lambda [currentGlyph] [begin \\
			if [not currentGlyph] : return nothing
			if [glyphList.(glyphList.length - 1).name === @{".quote" (".WF" + externEnv.$nWFGlyphs$)}] : glyphList.pop
			begin @::[steps.map formOf]
			set dependencyProfile.(currentGlyph.name) : getDependencyProfile currentGlyph
			return currentGlyph
		]] [create-glyph @{".quote" (".WF" + externEnv.$nWFGlyphs$)} $donothing$]]

define-macro branch : syntax-rules
	`[branch @::steps] : begin
		if [not externEnv.$nWFGlyphs$] : set externEnv.$nWFGlyphs$ 0
		inc externEnv.$nWFGlyphs$
		dirty `[[lambda [currentGlyph] [begin \\
			if [not currentGlyph] : return nothing
			if [glyphList.(glyphList.length - 1).name === @{".quote" (".WF" + externEnv.$nWFGlyphs$)}] : glyphList.pop
			begin @::[steps.map formOf]
			set dependencyProfile.(currentGlyph.name) : getDependencyProfile currentGlyph
			return currentGlyph
		]] [create-glyph @{".quote" (".WF" + externEnv.$nWFGlyphs$)} [lambda : begin [this.include currentGlyph true] [set this.advanceWidth currentGlyph.advanceWidth]]]]

define-macro save : syntax-rules
	`[save @::args] : dirty `[$save$.call currentGlyph @::args]

### COMMON FUNCTIONS
define [mix a b p] : a + (b - a) * p
define [linreg x0 y0 x1 y1 x] : y0 + (x - x0) * (y1 - y0) / (x1 - x0)
define [clamp l h x] : if (x < l) l : if (x > h) h x
define [fallback] : begin
	for [local j 0] (j < arguments.length) [inc j] : if (arguments.(j) !== nothing) : return arguments.(j)
	return nothing

define [TempFont] {.glyf {} .head {.} .hhea {.} ."OS/2" {.} .name {.} .post {.}}

define [anchorDeriv] : begin
	local h {.}
	foreach a [items-of arguments] : foreach k [items-of [Object.keys a.anchors]] : begin
		set h.(k) : new Anchor a.anchors.(k).x a.anchors.(k).y a.anchors.(k).type a.anchors.(k).mbx a.anchors.(k).mby
	return {.anchors h}

# contour tagging
define [tagged tag component] : begin
	set component.tag tag
	return component

export as build : define [buildFont para recursive recursiveCodes] : begin
	define variantSelector para.variantSelector
	define font this
	
	define glyphList font.glyf
	define glyphs {.}
	define unicodeGlyphs {}

	define UPM 1000
	
	# Progress indicator
	define [progress status] : if [not recursive] : begin
		if para.verbose : console.log "    \(font.name.uniqueSubFamily) : Done \(status)"
		#suggestGC
		return nothing

	# Key metrics
	define WIDTH para.width
	define SB para.sb
	define CAP para.cap
	define XH para.xheight
	define DESCENDER : fallback para.descender (XH - CAP)
	define CONTRAST : fallback para.contrast 1
	# Key metrics for symbols
	local parenTop ((XH * 0.625) + (CAP - XH) * 2.5)
	local parenBot ((XH * 0.625) - (CAP - XH) * 2.5)
	local parenMid [mix parenTop parenBot 0.5]
	local operTop : mix parenMid parenTop 0.8
	local operBot : mix parenMid parenBot 0.8
	
	# Transform constructors
	define [Italify angle shift] : begin
		local slope [Math.tan ([fallback angle para.slantAngle] / 180 * Math.PI)]
		return : new Transform 1 slope 0 1 [fallback shift : -slope * parenMid] 0
	define [Upright angle shift] [Italify angle shift :.inverse]
	define [Scale sx sy] : new Transform sx 0 0 [fallback sy sx] 0 0
	define [Translate x y] : new Transform 1 0 0 1 x y
	define [Rotate angle] : new Transform [Math.cos angle] (-[Math.sin angle]) [Math.sin angle] [Math.cos angle] 0 0
	
	define globalTransform : Italify para.slantAngle
	define TANSLANT   globalTransform.yx
	define SINSLANT : Math.sin (para.slantAngle / 180 * Math.PI)
	define COSSLANT : Math.cos (para.slantAngle / 180 * Math.PI)
	define HVCONTRAST : CONTRAST * COSSLANT + SINSLANT * TANSLANT
	
	# Orient parameters
	define UPWARD    : (-HVCONTRAST) <> 0
	define DOWNWARD  : HVCONTRAST <> 0
	define RIGHTWARD : TANSLANT <> 1
	define LEFTWARD  : (- TANSLANT) <> (-1)
	
	# Style parameters
	define O para.overshoot
	define OX para.overshootx
	define OXHOOK para.oxhook
	define HOOK para.hook
	define AHOOK para.ahook
	define SHOOK para.shook
	define RHOOK para.rhook
	define JHOOK para.jhook
	define FHOOK para.fhook
	define HOOKX para.hookx
	define SMOOTH para.smooth
	define SMALLSMOOTH para.smallsmooth
	define STROKE para.stroke
	define DOTSIZE : fallback para.dotsize STROKE
	define PERIODSIZE : fallback para.periodsize DOTSIZE
	define BARPOS : fallback para.barpos 0.5
	define GBARPOS : fallback para.gbarpos 0.5
	define PBARPOS : fallback para.pbarpos 0.5
	define EBARPOS : fallback para.ebarpos BARPOS
	define OVERLAYPOS para.overlaypos
	define FIVEBARPOS para.fivebarpos
	define LONGJUT para.longjut
	define JUT para.jut
	define VJUT para.vjut
	define ACCENT para.accent
	define ACCENTX para.accentx
	
	define CTHIN : fallback para.cthin 0.75
	define CTHINB : fallback para.cthinb 0.5
	
	define SLAB para.slab
	
	define TAILADJX : WIDTH * 0.2
	define TAILADJY : XH * 0.25
	define LBALANCE : LONGJUT * 0.04
	define IBALANCE : fallback para.ibalance (LONGJUT * 0.04)
	define JBALANCE : fallback para.jbalance 0
	define JBALANCE2 : fallback para.jbalance2 (STROKE * 0.25 + LBALANCE)
	define TBALANCE : fallback para.tbalance JBALANCE
	define TBALANCE2 : fallback para.tbalance2 TBALANCE
	define RBALANCE : fallback para.rbalance (JBALANCE * 0.3)
	define RBALANCE2 : fallback para.rbalance2 0
	define FBALANCE : fallback para.fbalance 0
	define ONEBALANCE : fallback para.onebalance 0
	
	# derived metrics
	define FULLWIDTH : if (para.spacing >= 2) 1000 WIDTH
	define FULLWIDTH1 : if (para.spacing >= 1) 1000 WIDTH
	define FULLWIDTH2 : if (para.spacing >= 2) 1000 WIDTH
	define FULLWIDTH3 : if (para.spacing >= 3) 1000 WIDTH
	
	define OXE : OX - O
	define ESS : STROKE * [fallback para.essx CONTRAST]
	define ESSQUESTION : STROKE * [fallback para.essxq CONTRAST]
	define XO : XH - O
	define CAPO : CAP - O
	define HALFSTROKE : STROKE / 2
	define RIGHTSB : WIDTH - SB
	define FWRSB : FULLWIDTH - SB
	define MIDDLE : WIDTH / 2
	define FWMIDDLE : FULLWIDTH / 2
	define CAPMIDDLE : CAP / 2
	define CAP_SMOOTH : CAP - SMOOTH
	define DOTRADIUS : DOTSIZE / 2
	define PERIODRADIUS : PERIODSIZE / 2
	define SIDEJUT : JUT - HALFSTROKE * HVCONTRAST
	
	define SMOOTHA : SMOOTH - TANSLANT * para.smoothadjust
	define SMOOTHB : SMOOTH + TANSLANT * para.smoothadjust
	define SMALLSMOOTHA : SMALLSMOOTH - TANSLANT * para.smoothadjust
	define SMALLSMOOTHB : SMALLSMOOTH + TANSLANT * para.smoothadjust
	
	define CORRECTION_OMIDX : TANSLANT * [linreg 18 1.3 126 0.9 STROKE]
	define CORRECTION_OMIDS : STROKE * CORRECTION_OMIDX
	
	# Blackness parameters
	# We will estimate blackness using lower-case 'e'
	define WHITENESS : ((XH - STROKE * 3) * (RIGHTSB - SB) * (1 / 3)) / (XH * (RIGHTSB - SB))
	define [adviceBlackness crowdedness] : Math.min STROKE ((RIGHTSB - SB) * (1 - WHITENESS) / (crowdedness * HVCONTRAST))
	define MVERTSTROKE : adviceBlackness : fallback para.lllcrowdedness (3 + 1 / 3)
	define OVERLAYSTROKE : adviceBlackness 3.75
	define OPERATORSTROKE : adviceBlackness 3.2
	define SHOULDERFINE : if para.shoulderfine (STROKE * para.shoulderfine) [adviceBlackness 10]
	
	define SUPERNESS : fallback para.superness 2
	define [superxy x] : Math.pow (1 - [Math.pow x SUPERNESS]) (1 / SUPERNESS)
	
	define [adviceSSmooth y sign] : begin
		local ss : y * 0.21 + STROKE * 0.22 * [clamp 1 2 : linreg 126 1 137 1.025 STROKE] + 0.035 * (RIGHTSB - SB)
		return : ss + sign * TANSLANT * para.smoothadjust * (ss / SMALLSMOOTH)
	define [adviceGlottalStopSmooth y sign] : ((y - STROKE) * 0.24 + STROKE * 0.625) + sign * TANSLANT * para.smoothadjust
	define [shoulderMidSlope _fine _stroke _dir] : 0.5 * HVCONTRAST * ([fallback _stroke STROKE] - [fallback _fine SHOULDERFINE]) / [fallback _stroke STROKE] + [fallback _dir 1] * TANSLANT
	
	# Anchor parameters
	define BASE Anchor.BASE
	define MARK Anchor.MARK

	define AS_BASE 'AS-BASE'
	define ALSO_METRICS 'ALSO-METRICS'
	
	define [tm anchor] : return : new Anchor
		* (anchor.x * globalTransform.xx + anchor.y * TANSLANT + globalTransform.x)
		* (anchor.x * globalTransform.xy + anchor.y * globalTransform.yy + globalTransform.y)
		* anchor.type
	
	define markAboveLower       {.anchors {.above       [tm : new Anchor MIDDLE  XH        BASE]}}
	define markAboveCap         {.anchors {.above       [tm : new Anchor MIDDLE  CAP       BASE]}}
	define markBelowLower       {.anchors {.below       [tm : new Anchor MIDDLE  DESCENDER BASE]}}
	define markBelowZero        {.anchors {.below       [tm : new Anchor MIDDLE  0         BASE]}}
	define markToprightLower    {.anchors {.topright    [tm : new Anchor RIGHTSB XH        BASE]}}
	define markToprightCap      {.anchors {.topright    [tm : new Anchor RIGHTSB CAP       BASE]}}
	define markBottomrightLower {.anchors {.bottomright [tm : new Anchor RIGHTSB DESCENDER BASE]}}
	define markBottomrightZero  {.anchors {.bottomright [tm : new Anchor RIGHTSB 0         BASE]}}
	
	define [StdAnchorGroup] : begin
		local a : anchorDeriv.apply null arguments
		set a.anchors.overlay : new Anchor
			* [mix a.anchors.below.x a.anchors.above.x OVERLAYPOS]
			* [mix a.anchors.below.y a.anchors.above.y OVERLAYPOS]
			* BASE
		set a.anchors.slash : new Anchor
			* [mix a.anchors.below.x a.anchors.above.x 0.5]
			* [mix a.anchors.below.y a.anchors.above.y 0.5]
			* BASE
		return a
	
	define capitalMarks : StdAnchorGroup markAboveCap markBelowZero markToprightCap markBottomrightZero
	define bMarks       : StdAnchorGroup markAboveCap markBelowZero markToprightCap markBottomrightZero
	define eMarks       : StdAnchorGroup markAboveLower markBelowZero markToprightLower markBottomrightZero
	define pMarks       : StdAnchorGroup markAboveLower markBelowLower markToprightLower markBottomrightLower
	define ifMarks      : StdAnchorGroup markAboveCap markBelowLower markToprightCap markBottomrightLower
	
	
	### Glyph slots and dependency profile generation (used for recursive subfonts)
	local dependencyProfile {.}
	local nTemp 0
	local nPending 0
	local pickHash : if recursive
		then : let [h {.}] : begin
			foreach j [items-of recursive] : set h.(j) j
			set nPending recursive.length
			* h
		else nothing
	define [getDependencyProfile glyph] : begin
		local dp {}
		foreach d [items-of glyph.dependencies] : begin
			dp.push d
			if dependencyProfile.(d): foreach [k : items-of dependencyProfile.(d)] : dp.push k
		return dp
	define [create-glyph] : match [Array.prototype.slice.call arguments 0]
		`[@name @actions] : begin
			if (pickHash && nPending <= 0) : begin
				if para.verbose : console.log "    *** Done recursive build for \[if (recursive.length > 3) [recursive.slice 0 3 :.concat {'...'} :.join ','] [recursive.join ',']] in \(font.name.uniqueSubFamily)"
				throw {.glyfMap glyphs}
			if (pickHash && [not pickHash.(name)]) : return nothing
			
			if para.verbose : console.log name
			local glyphObject [new Glyph name]
			glyphList.push glyphObject
			glyphs.(name) = glyphObject
			glyphObject.set-width WIDTH
			glyphObject.gizmo = globalTransform
			
			actions.call glyphObject
			
			set dependencyProfile.(name) : getDependencyProfile glyphObject
			dec nPending
			return glyphObject
		
		`[@actions] : begin
			local glyphName ('.temp-' + [set nTemp (nTemp + 1)])
			if para.verbose : console.log glyphName
			local glyphObject [new Glyph glyphName]
			glyphObject.set-width WIDTH
			glyphObject.gizmo = globalTransform
			actions.call glyphObject
			return glyphObject
	
	define [$save$ name unicode] : begin
		local t this
		local g : create-glyph name [lambda]
		if g : begin
			g.include t AS_BASE
			set g.advanceWidth t.advanceWidth
			set g.shortName t.shortName
			set g.dense t.dense
			if name : set dependencyProfile.(name) : getDependencyProfile g
		if (g && unicode) : begin
			g.assign-unicode unicode
			set unicodeGlyphs.(g.unicode.((g.unicode.length - 1))) g
		return g

	### Spiro constructions
	# Basic knots
	local [object
		g4 g2 corner flat curl close end straight
		widths heading unimportant important
		alsothru alsothruthem bezcontrols quadcontrols archv arcvh complexThru
		dispiro spiro-outline] : spirokit.SetupBuilders : object globalTransform CONTRAST STROKE Glyph para SUPERNESS

	###### HERE WE GO!
	
	### Metadata
	# Font names
	set para.family [para.family.trim]
	set para.style : [para.style.trim] || "Regular"
	set font.name.preferredFamily     para.family
	set font.name.preferredSubFamily  para.style
	if (para.style == 'Regular' || para.style == 'Bold' || para.style == 'Italic' || para.style == "Bold Italic") : then
		set font.name.fontFamily      para.family
		set font.name.fontSubFamily   para.style
	: else
		set font.name.fontFamily      : para.family + ' ' + [para.style.replace [regex ' Italic$'] '']
		set font.name.fontSubFamily   : if [[regex ' Italic$'].test para.style] 'Italic' 'Regular'
	set font.name.uniqueSubFamily     "\(para.family) \(para.style) \(para.version) (\(para.codename))"
	set font.name.version             para.version
	set font.name.fullName            : if (para.style != 'Regular') (para.family + ' ' + para.style) para.family
	set font.name.postScriptName      : font.name.fullName.replace [regex ' ' 'g'] '-'
	set font.name.copyright           para.copyright
	set font.name.licence             para.licence
	
	# Weight, width and slantness
	set font.'OS/2'.usWeightClass     para.weight
	set font.'OS/2'.bProportion       9 # Monospaced
	set font.'OS/2'.bWeight           : 1 + para.weight / 100
	set font.'OS/2'.fsSelection       : [if para.isBold 32 0] + [if para.isItalic 1 0] + [if ([not para.isBold] && [not para.isItalic]) 64 0] + 128
	set font.'OS/2'.sFamilyClass      : 8 * 0x100 + 9
	set font.'OS/2'.xAvgCharWidth     WIDTH
	set font.post.isFixedPitch        1
	set font.head.macStyle            : [if para.isBold 1 0] + [if para.isItalic 2 0]
	
	# Metric metadata
	# Note: we use 1000upm in design, and (1000 * upmsacle)upm in production, to avoid rounding error.
	
	let [asc : para.leading * CAP / (CAP - DESCENDER)] [desc : para.leading * DESCENDER / (CAP - DESCENDER)] : begin
		set font.head.unitsPerEm          1000
		set font.hhea.ascent              asc
		set font.'OS/2'.usWinAscent       asc
		set font.'OS/2'.sTypoAscender     asc
		
		set font.hhea.descent             DESCENDER
		set font.'OS/2'.usWinDescent      [Math.abs desc]
		set font.'OS/2'.sTypoDescender    desc
		
		set font.hhea.lineGap             (para.leading - asc + DESCENDER)
		set font.'OS/2'.sTypoLineGap      (para.leading - asc + desc)
		
		set font.'OS/2'.sxHeight          XH
		set font.'OS/2'.sCapHeight        CAP
		set font.post.italicAngle         (0 - para.slantAngle)
	
	# Necessary notdef glyph
	sketch # .notdef
		start-from SB 0
		line-to    SB CAP
		line-to    RIGHTSB CAP
		line-to    RIGHTSB 0
		
		start-from (SB + STROKE) STROKE
		line-to    (RIGHTSB - STROKE) STROKE
		line-to    (RIGHTSB - STROKE) (CAP - STROKE)
		line-to    (SB + STROKE) (CAP - STROKE)
		
		save '.notdef'
	
	# Space
	sketch # space
		set-width WIDTH
		include eMarks
		save 'space' ' '

	### HERE WE GO
	$$include 'glyphs/common-shapes.ptl'
	$$include 'glyphs/overmarks.ptl'
	
	# Unified letters
	$$include 'glyphs/letters-unified-basic.ptl'
	$$include 'glyphs/letters-unified-extended.ptl'
	
	# Numbers
	$$include 'glyphs/numbers.ptl'
	
	# Symbols
	$$include 'glyphs/symbol-punctuation.ptl'
	$$include 'glyphs/symbol-math.ptl'
	$$include 'glyphs/symbol-letter.ptl'
	$$include 'glyphs/symbol-geometric.ptl'
	$$include 'glyphs/symbol-other.ptl'
	
	# Autobuilds
	set font.features {.}
	$$include 'glyphs/autobuilds.ptl'
	
	set font.glyfMap glyphs
	return font