summary refs log tree commit diff stats
path: root/lib/wrappers/gtk/pangoutils.nim
blob: e6f3ab94c89862ad0643fb90f82bb54e102b0cc0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{.deadCodeElim: on.}

import
  glib2, pango

type
  pint32* = ptr int32

proc pango_split_file_list*(str: cstring): PPchar{.cdecl, dynlib: pangolib,
    importc: "pango_split_file_list".}
proc pango_trim_string*(str: cstring): cstring{.cdecl, dynlib: pangolib,
    importc: "pango_trim_string".}
proc pango_read_line*(stream: TFile, str: PGString): gint{.cdecl,
    dynlib: pangolib, importc: "pango_read_line".}
proc pango_skip_space*(pos: PPchar): gboolean{.cdecl, dynlib: pangolib,
    importc: "pango_skip_space".}
proc pango_scan_word*(pos: PPchar, OutStr: PGString): gboolean{.cdecl,
    dynlib: pangolib, importc: "pango_scan_word".}
proc pango_scan_string*(pos: PPchar, OutStr: PGString): gboolean{.cdecl,
    dynlib: pangolib, importc: "pango_scan_string".}
proc pango_scan_int*(pos: PPchar, OutInt: pint32): gboolean{.cdecl,
    dynlib: pangolib, importc: "pango_scan_int".}
proc pango_config_key_get(key: cstring): cstring{.cdecl, dynlib: pangolib,
    importc: "pango_config_key_get".}
proc pango_lookup_aliases(fontname: cstring, families: PPPchar,
                          n_families: pint32){.cdecl, dynlib: pangolib,
    importc: "pango_lookup_aliases".}
proc pango_parse_style*(str: cstring, style: PPangoStyle, warn: gboolean): gboolean{.
    cdecl, dynlib: pangolib, importc: "pango_parse_style".}
proc pango_parse_variant*(str: cstring, variant: PPangoVariant, warn: gboolean): gboolean{.
    cdecl, dynlib: pangolib, importc: "pango_parse_variant".}
proc pango_parse_weight*(str: cstring, weight: PPangoWeight, warn: gboolean): gboolean{.
    cdecl, dynlib: pangolib, importc: "pango_parse_weight".}
proc pango_parse_stretch*(str: cstring, stretch: PPangoStretch, warn: gboolean): gboolean{.
    cdecl, dynlib: pangolib, importc: "pango_parse_stretch".}
proc pango_get_sysconf_subdirectory(): cstring{.cdecl, dynlib: pangolib,
    importc: "pango_get_sysconf_subdirectory".}
proc pango_get_lib_subdirectory(): cstring{.cdecl, dynlib: pangolib,
    importc: "pango_get_lib_subdirectory".}
proc pango_log2vis_get_embedding_levels*(str: Pgunichar, len: int32,
    pbase_dir: PPangoDirection, embedding_level_list: Pguint8): gboolean{.cdecl,
    dynlib: pangolib, importc: "pango_log2vis_get_embedding_levels".}
proc pango_get_mirror_char*(ch: gunichar, mirrored_ch: Pgunichar): gboolean{.
    cdecl, dynlib: pangolib, importc: "pango_get_mirror_char".}
proc pango_language_get_sample_string*(language: PPangoLanguage): cstring{.
    cdecl, dynlib: pangolib, importc: "pango_language_get_sample_string".}
an>{.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, process: TPassProcess, close: TPassClose] TPassData* = tuple[input: PNode, closeOutput: PNode] TPasses* = openArray[TPass] # a pass is a tuple of procedure vars ``TPass.close`` may produce additional # nodes. These are passed to the other close procedures. # This mechanism used to be used for the instantiation of generics. proc makePass*(open: TPassOpen = nil, openCached: TPassOpenCached = nil, process: TPassProcess = nil, close: TPassClose = nil): TPass = result.open = open result.openCached = openCached result.close = close result.process = process # the semantic checker needs these: var gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.} gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.} # implementation proc skipCodegen*(n: PNode): bool {.inline.} = # can be used by codegen passes to determine whether they should do # something with `n`. Currently, this ignores `n` and uses the global # error count instead. result = msgs.gErrorCounter > 0 proc astNeeded*(s: PSym): bool = # The ``rodwrite`` module uses this to determine if the body of a proc # needs to be stored. The passes manager frees s.sons[codePos] when # appropriate to free the procedure body's memory. This is important # to keep memory usage down. if (s.kind in {skMethod, skProc}) and ({sfCompilerProc, sfCompileTime} * s.flags == {}) and (s.typ.callConv != ccInline) and (s.ast.sons[genericParamsPos].kind == nkEmpty): result = false # XXX this doesn't really make sense with excessive CTFE else: result = true const maxPasses = 10 type TPassContextArray = array[0..maxPasses - 1, PPassContext] var gPasses: array[0..maxPasses - 1, TPass] gPassesLen*: int proc clearPasses* = gPassesLen = 0 proc registerPass*(p: TPass) = gPasses[gPassesLen] = p inc(gPassesLen) proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; m: TPassData): TPassData = var c = p.open(g, module, cache) result.input = p.process(c, m.input) result.closeOutput = if p.close != nil: p.close(c, m.closeOutput) else: m.closeOutput proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache; passes: TPasses) = var passdata: TPassData passdata.input = nodes for pass in passes: passdata = carryPass(g, pass, module, cache, passdata) proc openPasses(g: ModuleGraph; a: var TPassContextArray; module: PSym; cache: IdentCache) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].open): a[i] = gPasses[i].open(g, module, cache) else: a[i] = nil proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym, rd: PRodReader) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): a[i] = gPasses[i].openCached(g, module, rd) if a[i] != nil: a[i].fromCache = true else: a[i] = nil proc closePasses(a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) a[i] = nil # free the memory here proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = # this implements the code transformation pipeline var m = n for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].process): m = gPasses[i].process(a[i], m) if isNil(m): return false result = true proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = # this implements the code transformation pipeline var m = n for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) proc closePassesCached(a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) a[i] = nil # free the memory here proc resolveMod(module, relativeTo: string): int32 = let fullPath = findModule(module, relativeTo) if fullPath.len == 0: result = InvalidFileIDX else: result = fullPath.fileInfoIdx proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, a: var TPassContextArray; m: PSym) = # XXX fixme this should actually be relative to the config file! let relativeTo = m.info.toFullPath for module in items(implicits): # implicit imports should not lead to a module importing itself if m.position != resolveMod(module, relativeTo): var importStmt = newNodeI(nodeKind, gCmdLineInfo) var str = newStrNode(nkStrLit, module) str.info = gCmdLineInfo importStmt.addSon str if not processTopLevelStmt(importStmt, a): break proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, rd: PRodReader; cache: IdentCache): bool {.discardable.} = var p: TParsers a: TPassContextArray s: PLLStream fileIdx = module.fileIdx if rd == nil: openPasses(graph, a, module, cache) if stream == nil: let filename = fileIdx.toFullPathConsiderDirty s = llStreamOpen(filename, fmRead) if s == nil: rawMessage(errCannotOpenFile, filename) return false else: s = stream while true: openParsers(p, fileIdx, s, cache) if sfSystemModule notin module.flags: # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only # for the interactive mode. processImplicits implicitImports, nkImportStmt, a, module processImplicits implicitIncludes, nkIncludeStmt, a, module while true: var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break if sfNoForward in module.flags: # read everything, no streaming possible var sl = newNodeI(nkStmtList, n.info) sl.add n while true: var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break sl.add n discard processTopLevelStmt(sl, a) break elif not processTopLevelStmt(n, a): break closeParsers(p) if s.kind != llsStdIn: break closePasses(a) # id synchronization point for more consistent code generation: idSynchronizationPoint(1000) else: openPassesCached(graph, a, module, rd) var n = loadInitSection(rd) for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) closePassesCached(a) result = true