diff options
Diffstat (limited to 'nix/builder/parser.nix')
-rw-r--r-- | nix/builder/parser.nix | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/nix/builder/parser.nix b/nix/builder/parser.nix new file mode 100644 index 0000000..eb6f75e --- /dev/null +++ b/nix/builder/parser.nix @@ -0,0 +1,141 @@ +# Parse go.mod in Nix +# Returns a Nix structure with the contents of the go.mod passed in +# in normalised form. + +let + inherit (builtins) elemAt mapAttrs split foldl' match filter typeOf hasAttr length; + + # Strip lines with comments & other junk + stripStr = s: elemAt (split "^ *" (elemAt (split " *$" s) 0)) 2; + stripLines = initialLines: foldl' (acc: f: f acc) initialLines [ + # Strip comments + (lines: map + (l: stripStr (elemAt (splitString "//" l) 0)) + lines) + + # Strip leading tabs characters + (lines: map (l: elemAt (match "(\t)?(.*)" l) 1) lines) + + # Filter empty lines + (filter (l: l != "")) + ]; + + # Parse lines into a structure + parseLines = lines: (foldl' + (acc: l: + let + m = match "([^ )]*) *(.*)" l; + directive = elemAt m 0; + rest = elemAt m 1; + + # Maintain parser state (inside parens or not) + inDirective = + if rest == "(" then directive + else if rest == ")" then null + else acc.inDirective + ; + + in + { + data = (acc.data // ( + if directive == "" && rest == ")" then { } + else if inDirective != null && rest == "(" && ! hasAttr inDirective acc.data then { + ${inDirective} = { }; + } + else if rest == "(" || rest == ")" then { } + else if inDirective != null then { + ${inDirective} = acc.data.${inDirective} // { ${directive} = rest; }; + } else if directive == "replace" then + ( + let + segments = split " => " rest; + getSegment = elemAt segments; + in + assert length segments == 3; { + replace = acc.data.replace // { + ${getSegment 0} = "=> ${getSegment 2}"; + }; + } + ) + else { + ${directive} = rest; + } + ) + ); + inherit inDirective; + }) + { + inDirective = null; + data = { + require = { }; + replace = { }; + exclude = { }; + }; + } + lines + ).data; + + normaliseDirectives = data: ( + let + normaliseString = s: + let + m = builtins.match "([^ ]+) (.+)" s; + in + { + ${elemAt m 0} = elemAt m 1; + }; + require = data.require or { }; + replace = data.replace or { }; + exclude = data.exclude or { }; + in + data // { + require = + if typeOf require == "string" then normaliseString require + else require; + replace = + if typeOf replace == "string" then normaliseString replace + else replace; + } + ); + + parseVersion = ver: + let + m = elemAt (match "([^-]+)-?([^-]*)-?([^-]*)" ver); + v = elemAt (match "([^+]+)\\+?(.*)" (m 0)); + in + { + version = v 0; + versionSuffix = v 1; + date = m 1; + rev = m 2; + }; + + parseReplace = data: ( + data // { + replace = + mapAttrs + (_: v: + let + m = match "=> ([^ ]+) (.+)" v; + m2 = match "=> (.*+)" v; + in + if m != null then { + goPackagePath = elemAt m 0; + version = elemAt m 1; + } else { + path = elemAt m2 0; + }) + data.replace; + } + ); + + splitString = sep: s: filter (t: t != [ ]) (split sep s); + +in +contents: +foldl' (acc: f: f acc) (splitString "\n" contents) [ + stripLines + parseLines + normaliseDirectives + parseReplace +] |