peg-cmake is a simple CMake parser written in javascript. It aims to provide a core lib for tools such as formatting, refactoring, etc...
The library is under developement and not stable.
npm install peg-cmake
var CMake = require('peg-cmake');
var fs = require('fs');
function traversAST(ast, matcher) {
ast.forEach((element)=>{
if(matcher[element.type])
matcher[element.type](element);
});
}
fs.readFile('CMakeLists.txt', 'utf8', function (err,data) {
if (!err) {
try {
var ast = CMake.parse(data);
// print all functions defined in the script
function FunctionsVisitor() {
this._func = (elt)=>{
console.log("- " +elt.identifier + " : line:" + elt.location.start.line )
}
this.macro = this._func;
this.function = this._func;
this.if=(elt)=>{
traversAST(elt.body, this);
elt.elseif.foreach((e)=>{traversAST(elt.body, this);});
if(elt.else)traversAST(elt.else.body, this);
}
};
traversAST(result, new FindFunctions());
}catch(e) {
console.log(e.name + " line " + e.location.start.line
+ ", " + e.location.start.column
+ "\n"+ e.message);
}
}
});
The the parse result is an array of node.
Each node owns at least a type
which can be one of the following :
"bracket_argument"
"bracket_comment"
"command_invocation"
"foreach"
"function"
"identifier"
"if"
"line_comment"
"macro"
"newline"
"quoted_argument"
"script"
"unquoted_argument"
"while"
and a location :
{
"start": {
"offset": 31,
"line": 1,
"column": 32
},
"end": {
"offset": 43,
"line": 1,
"column": 44
}
}
**Type** | **CMake** | **ASTNode** |
`line_comment` |
# A single line comment
|
{
"type": "line_comment",
"value": " A single line comment"
}
|
`bracket_comment` |
#[[This is a bracket comment.
It runs until the close bracket.]]
message("1st Arg\n" #[[Bracket Comment]] "2nd Arg") |
{
"type": "bracket_comment",
"value": "Bracket Comment"
}
|
`newline` |
{
"type":'newline'
} |
|
`command_invocation` |
message(FATAL "Hello") |
{
"type": "command_invocation",
"name": "message",
"arguments": [
{ "type" = "unquoted_argument" /*...*/ },
{ "type" = "quoted_argument" /*...*/ }
]
} |
`bracket_argument` |
message([=[
This is the first line in a
bracket argument with bracket length 1.
No \-escape sequences or ${variable}
references are evaluated.
This is always one argument even
though it contains a ; character.
The text does not end on a closing
bracket of length 0 like ]].
It does end in a closing bracket
of length 1.
]=]) |
{
"type": "bracket_argument",
"value": "This is [...] of length 1.",
"len": 1
} |
`if` |
if(TRUE)
elseif(PREDICATE)
else()
endif() |
{
"type": "if",
"predicate" : [{"type":"unquoted_argument", "value":"TRUE"}],
"body": [],
"elseif" : [
{
"predicate" : [{"type":"unquoted_argument", "value":"PREDICATE"}],
"body": []
}
],
"else" : {
"predicate" : [{"type":"unquoted_argument", "value":"TRUE"}],
"body": []
}
} |
`function` |
function(my_func ARG)
# body
endfunction() |
{
"type": "function",
"identifier": {type:"identifier", value:"my_func"},
"arguments": [ {"type": "unquoted_argument" /*, ...*/} ]
"body": [
{ "type" = "line_comment" /*...*/ }
]
} |
`macro` |
macro(my_macro ARG)
# body
endmacro() |
{
"type": "macro",
"name": "my_macro",
"arguments": [ {"type": "unquoted_argument" /*, ...*/} ]
"body": [
{ "type" = "line_comment" /*...*/ }
]
} |
`foreach` |
foreach(F ${FILES})
# body
endforeach() |
{
"arguments": [ {"type": "unquoted_argument", "value": "F"},
{"type": "unquoted_argument", "value": "${FILES}"} ]
"body": [
{ "type" = "line_comment" /*...*/ }
]
} |
`while` |
while(F ${FILES})
# body
endwhile() |
{
"arguments": [ {"type": "unquoted_argument", "value": "F"},
{"type": "unquoted_argument", "value": "${FILES}"} ]
"body": [
{ "type" = "line_comment" /*...*/ }
]
} |
- fix :
CMake versions prior to 2.8.12 silently accept an Unquoted Argument or a Quoted Argument immediately following a Quoted Argument and not separated by any whitespace. For compatibility, CMake 2.8.12 and higher accept such code but produce a warning.
- add experimental cmake formater
- Thes buffer must end with "\n", as a workaround the parse function append a new line to the buffer passed as argument.