Browse Source

Initial commit

master
Sven Slootweg 4 years ago
parent
commit
a9e16640ca
  1. 7
      .gitignore
  2. 1
      .npmignore
  3. 29
      README.md
  4. 31
      gulpfile.js
  5. 3
      index.js
  6. 27
      package.json
  7. 179
      src/expression.pegjs
  8. 7
      src/index.js
  9. 16
      test.js
  10. 1
      test/function-call-default.nix
  11. 1
      test/function-call-parens.nix
  12. 7
      test/let-block.nix
  13. 1
      test/nested-function-call.nix
  14. 7
      test/set-function.nix
  15. 5
      test/simple.nix

7
.gitignore

@ -1,5 +1,2 @@
# https://git-scm.com/docs/gitignore
# https://help.github.com/articles/ignoring-files
# Example .gitignore files: https://github.com/github/gitignore
/bower_components/
/node_modules/
/node_modules/
/lib/

1
.npmignore

@ -0,0 +1 @@
/node_modules/

29
README.md

@ -0,0 +1,29 @@
# nix-parser
TODO
## License
[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer. A donation and/or attribution are appreciated, but not required.
## Donate
My income consists largely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)!
You can donate using Bitcoin, PayPal, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else.
## Contributing
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the files in `src/`, not those in `lib/`.
Build tool of choice is `gulp`; simply run `gulp` while developing, and it will watch for changes.
Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.
## Usage
TODO
## API
TODO

31
gulpfile.js

@ -0,0 +1,31 @@
var gulp = require("gulp");
var presetES2015 = require("@joepie91/gulp-preset-es2015");
var presetPegjs = require("@joepie91/gulp-preset-pegjs");
var sources = {
babel: ["src/**/*.js"],
pegjs: ["src/**/*.pegjs"]
}
gulp.task('babel', function() {
return gulp.src(sources.babel)
.pipe(presetES2015({
basePath: __dirname
}))
.pipe(gulp.dest("lib/"));
});
gulp.task('pegjs', function() {
return gulp.src(sources.pegjs)
.pipe(presetPegjs({
basePath: __dirname
}))
.pipe(gulp.dest("lib/"));
});
gulp.task("watch", function () {
gulp.watch(sources.babel, ["babel"]);
gulp.watch(sources.pegjs, ["pegjs"]);
});
gulp.task("default", ["babel", "pegjs", "watch"]);

3
index.js

@ -0,0 +1,3 @@
'use strict';
module.exports = require("./lib");

27
package.json

@ -0,0 +1,27 @@
{
"name": "nix-parser",
"version": "1.0.0",
"description": "Parser for Nix expressions",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "http://git.cryto.net/joepie91/node-nix-parser.git"
},
"keywords": [
"nix",
"parser",
"nixos"
],
"author": "Sven Slootweg",
"license": "WTFPL",
"dependencies": {},
"devDependencies": {
"@joepie91/gulp-preset-es2015": "^1.0.1",
"@joepie91/gulp-preset-pegjs": "^1.0.0",
"babel-preset-es2015": "^6.6.0",
"gulp": "^3.9.1"
}
}

179
src/expression.pegjs

@ -0,0 +1,179 @@
{
function concatRepeat(first, rest, restIndex) {
return [first].concat(rest.map(function(item) {
return item[restIndex];
}));
}
function unnestFunctionCalls(first, nested, last) {
var callStack = nested.concat([last]);
function createFunctionCall(i) {
var func;
if (i === 0) {
func = first;
} else {
func = createFunctionCall(i - 1);
}
return {
type: "functionCall",
argument: callStack[i],
function: func
};
}
return createFunctionCall(callStack.length - 1);
}
}
start
= _ expression:expression* _ { return expression; }
// Character classes
whitespace
= "\t"
/ "\n"
/ "\r"
/ " "
stringLiteralCharacter
= !('"' / "\\") char:. { return char; }
/ "\\" escapableCharacter
numberLiteralCharacter
= [0-9.]
escapableCharacter
= '"'
/ "n"
/ "t"
/ "r"
commentCharacter
= [^\n\r]
// Literals
stringLiteral
= '"' chars:stringLiteralCharacter+ '"' { return {type: "stringLiteral", value: chars.join("")} }
numberLiteral
= chars:numberLiteralCharacter+ { return {type: "numberLiteral", value: chars.join("")} }
// Utilities
_
= (whitespace / comment)* {}
// Language constructs
expression
= additive
/ operand
comment
= "#" chars:commentCharacter* _ { return {type: "comment", text: chars.join("")} }
operand
= group
/ letBlock
/ stringLiteral
/ numberLiteral
/ functionDefinition
/ recursiveSet
/ set
/ possiblyNestedFunctionCall
/ identifier
additive
= left:subtractive
_ "+"
_ right:additive { return {type: "operation", operator: "+", left: left, right: right} }
/ subtractive
subtractive
= left:multiplicative
_ "-"
_ right:subtractive { return {type: "operation", operator: "-", left: left, right: right} }
/ multiplicative
multiplicative
= left:operand
_ "*"
_ right:multiplicative { return {type: "operation", operator: "*", left: left, right: right} }
/ operand
identifier
= literal:stringLiteral { return {type: "identifier", identifier: literal.value} }
/ chars:[a-z.]i+ { return {type: "identifier", identifier: text()} }
group
= "("
_ expression:expression
_ ")" { return {type: "group", expression: expression} }
functionDefinition
= argument:functionDefinitionArgument
_ ":"
_ body:expression { return {type: "functionDefinition", argument: argument, body: body} }
functionDefinitionArgument
= identifier
/ setPattern
//functionCallWithParens
// = functionName:expression "("
// _ arg:expression
// _ ")" {return {type: "functionCall", name: functionName, argument: arg} }
//
//functionCallWithoutParens
// = functionName:expression " "
// _ arg:expression {return {type: "functionCall", name: functionName, argument: arg} }
//
//functionCall
// = functionCallWithParens
// / functionCallWithoutParens
possiblyNestedFunctionCall
= first:expression nested:expression* last:expression { return unnestFunctionCalls(first, nested, last); }
assignment
= _ identifier:identifier
_ "="
_ expression:expression
_ ";" { return {type: "assignment", identifier: identifier, expression: expression} }
assignmentList
= items:assignment* { return items; }
bindingList
= items:assignment* { return {type: "bindings", assignments: items} }
set
= "{"
_ items:assignmentList
_ "}" { return {type: "set", assignments: items} }
recursiveSet
= "rec"
_ setData:set { return {type: "recursiveSet", assignments: setData.assignments} }
letBlock
= "let"
_ bindingList:bindingList
_ "in"
_ expression:expression { return {type: "letBlock", bindings: bindingList.assignments, expression: expression} }
setPattern
= "{"
_ args:setPatternVariableList
_ "}" { return {type: "setPattern", variables: args} }
setPatternVariableList
= firstItem:setPatternVariable otherItems:(_ "," _ setPatternVariable)* { return concatRepeat(firstItem, otherItems, 3); }
setPatternVariable
= restParameter
/ identifier
restParameter
= "..." { return {type: "restParameter"} }

7
src/index.js

@ -0,0 +1,7 @@
'use strict';
const expressionParser = require("./expression");
module.exports = function(body) {
return expressionParser.parse(body);
}

16
test.js

@ -0,0 +1,16 @@
'use strict';
const util = require("util");
const fs = require("fs");
const parse = require("./");
function fullInspect(obj) {
return util.inspect(obj, {colors: true, depth: null, customInspect: false})
}
try {
let contents = fs.readFileSync(process.argv[2]).toString();
console.log(fullInspect(parse(contents)));
} catch (err) {
console.log(fullInspect(err))
}

1
test/function-call-default.nix

@ -0,0 +1 @@
builtins.isInt 4

1
test/function-call-parens.nix

@ -0,0 +1 @@
builtins.isInt(4)

7
test/let-block.nix

@ -0,0 +1,7 @@
let
h = "Hello";
w = "World";
in
{
helloWorld = h + X + X;
}

1
test/nested-function-call.nix

@ -0,0 +1 @@
builtins.isInt 4 10 12

7
test/set-function.nix

@ -0,0 +1,7 @@
{ system, bootStdenv, noSysDirs, gccWithCC, gccWithProfiling
, config, crossSystem, platform, lib
, pkgsWithOverrides
, ... }:
rec {
thing = config;
}

5
test/simple.nix

@ -0,0 +1,5 @@
# code goes here
{
v="understood"; # Another comment
b=2;
}
Loading…
Cancel
Save