nimble/parser.nim

193 lines
5 KiB
Nim

import parsecfg, streams, strutils, os
type
TProject* = object
name*: String # Req
version*: String # Req
author*: String # Req
category*: String # Req
desc*: String # Req
license*: String
homepage*: String
library*: bool
depends*: seq[tuple[name, vRange: string]] # Dependencies
modules*: seq[string] # ExtraModules
files*: seq[string] # files
executable*: bool
exeFile*: string
unknownFields*: seq[string] # TODO:
confDir*: string # Directory of the babel file, "" if current work dir.
EParseErr* = object of EInvalidValue
proc initProj(): TProject =
result.name = ""
result.version = ""
result.author = ""
result.category = ""
result.desc = ""
result.license = ""
result.homepage = ""
result.library = False
result.executable = False
result.depends = @[]
result.modules = @[]
result.files = @[]
result.exeFile = ""
result.unknownFields = @[]
result.confDir = ""
proc parseList(s: string): seq[string] =
result = @[]
var many = s.split({',', ';'})
for i in items(many):
result.add(i.strip())
proc skipUntil(s, token: string, o: var string): int =
## Captures each char until `token` is found, sets `o` to the captured string,
## and returns the number of characters captured.
var i = 0
while True:
case s[i]
of '\0':
break
else:
var found = False
for t in 0..len(token)-1:
if s[i+t] == token[t]:
found = True
else:
found = False
break
if found:
break
inc(i)
o = copy(s, 0, i-1)
return i
proc parseDepends(s: string): seq[tuple[name, vRange: string]] =
result = @[]
var many = s.split({',', ';'})
for i in items(many):
var stripped = i.strip()
var name = ""
var index = skipUntil(stripped, " ", name)
var vRange = stripped.copy(index)
result.add((name.strip(), vRange.strip()))
proc parseErr(p: TCfgParser, msg: string) =
raise newException(EParseErr, "(" & $p.getLine() & ", " &
$p.getColumn() & ") " & msg)
proc parseBabel*(file: string): TProject =
result = initProj()
result.confDir = splitFile(file).dir
var f = newFileStream(file, fmRead)
if f != nil:
var p: TCfgParser
open(p, f, file)
var section: String = ""
while true:
var e = next(p)
case e.kind
of cfgEof:
break
of cfgKeyValuePair:
case section
of "package":
case normalize(e.key):
of "name":
result.name = e.value
of "version":
result.version = e.value
of "author":
result.author = e.value
of "category":
result.category = e.value
of "description":
result.desc = e.value
of "homepage":
result.homepage = e.value
of "license":
result.license = e.value
else:
p.parseErr("Unknown key: " & e.key)
of "library":
case normalize(e.key)
of "depends":
result.depends = e.value.parseDepends()
of "files":
result.files = e.value.parseList()
of "exposedmodules":
result.modules = e.value.parseList()
else:
p.parseErr("Unknown key: " & e.key)
of "exe":
case normalize(e.key)
of "depends":
result.depends = e.value.parseDepends()
of "files":
result.files = e.value.parseList()
of "exe":
result.exeFile = e.value
else:
p.parseErr("Unknown key: " & e.key)
else:
p.parseErr("Unknown section: " & section)
of cfgSectionStart:
section = normalize(e.section)
case normalize(e.section):
of "library":
result.library = True
of "exe":
result.executable = True
of "package":
nil
else:
p.parseErr("Unknown section: " & section)
of cfgError:
p.parseErr(e.msg)
of cfgOption:
p.parseErr("Unknown option: " & e.key)
close(p)
else:
raise newException(EIO, "Cannot open " & file)
proc isEmpty(s: string): Bool = return s == ""
proc verify*(proj: TProject): string =
## Checks whether the required fields have been specified.
if isEmpty(proj.name) or isEmpty(proj.version) or isEmpty(proj.author) or
isEmpty(proj.category) or isEmpty(proj.desc):
return "Missing required fields."
elif proj.library == false and proj.executable == false:
return "Either a valid Library needs to be specified or a valid Bin."
elif proj.library == true and proj.modules.len() == 0:
return "A valid library needs at least one ExposedModule listed."
# TODO: Rules for Bin.
return ""
when isMainModule:
for i in items(parseList("test, asdasd >sda; jsj, kk >>, sd")):
echo(i)
var project = parseBabel("babel.babel")
echo project.library
echo()
var o = ""
echo skipUntil("nimrod >= 0.8.10", " ", o)
echo(o)