LemonJS/process.js

371 lines
9.6 KiB
JavaScript

/**
* Created by Aleksey Chichenkov <a.chichenkov@initi.ru> on 1/28/19.
*/
var fs = require("fs");
var Lexer = require('./lexer.js');
var tokens = (function () {
var std = (function () {
var protos = "__protos__";
var keys = "__keys__";
/**
* Return unique data
*
* @param {Object[]} _arr - prototypes of inheritance classes
* @param {Object} _main - prototype of resulting class
*
* @return {Object}
* */
var unique = function (_arr, _main) {
var result = Object.create(null);
var to_remove = [];
for (var i = 0, e = _arr.length; i != e; ++i) {
var item = _arr[i];
for (var key in item) {
if (key in result) {
to_remove.push(key);
continue;
}
result[key] = item[key];
}
if (keys in item) {
for (var ii = 0, ee = item[keys].length; ii != ee; ++ii) {
var key = item[keys][ii];
if (key in result) {
to_remove.push(key);
continue;
}
result[key] = item[key];
}
}
}
for (var i = 0; i != to_remove.length; ++i) {
delete result[to_remove[i]];
}
for (var key in _main) {
result[key] = _main[key];
}
return result;
};
/**
* Create OOP class
*
* @param {Function[]} _constrs - inheritance classes
* @param {Object} _proto - prototype of resulting class
* @param {Object?} _static - static data
*
* @return {Function}
* */
var class_creator = function (_constrs, _proto, _static) {
_constrs = _constrs || [];
_proto = _proto || [];
_static = _static || [];
var constr;
if (_proto && _proto.hasOwnProperty("constructor")) {
constr = _proto.constructor;
delete _proto.constructor;
} else {
constr = function () {
for (var i = 0; i != _constrs.length; ++i) {
_constrs[i].apply(this, arguments);
}
};
}
var proto = Object.create(null);
Object.defineProperty(proto, protos, {
"value": []
});
Object.defineProperty(proto, keys, {
"value": []
});
/************************FOR MEMBERS*******************************/
for (var i = 0, e = _constrs.length; i != e; ++i) {
proto[protos].push(_constrs[i].prototype);
}
var m_un = unique(proto[protos], _proto);
for (var key in m_un) {
proto[keys].push(key);
Object.defineProperty(proto, key, {
"value": m_un[key]
});
}
/************************FOR MEMBERS END***************************/
/************************FOR STATICS*******************************/
var s_un = unique(_constrs, _static);
for (var key in s_un) {
Object.defineProperty(constr, key, {
"value": s_un[key],
"enumerable": true
});
}
/************************FOR STATICS END***************************/
Object.defineProperties(constr, {
"pr": {
"value": proto
},
"prototype": {
"value": proto
}
});
Object.freeze(proto);
Object.freeze(constr);
return constr;
};
/**
* Check if target has prototype
*
* @param {Object} _target - checkable instance
* @param {Object} _proto - posible prototype
*
* */
var check = function (_target, _proto) {
for (var i = 0; i != _target[protos].length; ++i) {
var t_proto = _target[protos][i];
if (t_proto == _proto) {
return true;
}
if (t_proto[protos]) {
if (check(t_proto, _proto))
return true;
}
}
return false;
};
/**
* Check if target is instance of class
*
* @param {Object} _target - checkable instance
* @param {Function} _constr - posible constructor
*
* */
var class_check = function (_target, _constr) {
if (_target instanceof _constr) {
return true;
}
return check(_target, _constr.prototype);
};
return {
class: class_creator,
class_check: class_check
};
})();
var tools = {
merge: function (_obj) {
var target = Object.create(null);
var i = 0, e = arguments.length;
for (; i != e; ++i) {
var options = arguments[i];
for (var key in options) {
if (options[key] === undefined && target === options[key])
continue;
target[key] = options[key];
}
}
return target;
}
};
var Node = std.class([], {
constructor: function Node(_options) {
var base = tools.merge({
children: []
}, _options);
this.children = base.children;
},
add: function (_n) {
this.children.push(_n);
return this;
}
});
var Lexeme = std.class([Node], {
constructor: function Lexeme(_options) {
var base = tools.merge({
start: -1,
end: -1,
type: null,
value: null
}, _options);
Node.call(this, base);
this.start = base.start;
this.end = base.end;
this.type = base.type;
this.value = base.value;
}
});
var Rule = std.class([Node], {
constructor: function NonTerminal(_options) {
var base = tools.merge({}, _options);
Node.call(this, base);
}
});
var string_literal = std.class([Rule], {
constructor: function string_literal(_options) {
var base = tools.merge({}, _options);
Rule.call(this, base);
}
});
var integer_literal = std.class([Rule], {
constructor: function integer_literal(_options) {
var base = tools.merge({}, _options);
Rule.call(this, base);
}
});
var id = std.class([Rule], {
constructor: function id(_options) {
var base = tools.merge({}, _options);
Rule.call(this, base);
}
});
var literal = std.class([Rule], {
constructor: function literal(_options) {
var base = tools.merge({}, _options);
Rule.call(this, base);
}
});
var eq = std.class([Rule], {
constructor: function eq(_options) {
var base = tools.merge({
id: null,
EQ: null,
literal: null
}, _options);
Rule.call(this, base);
this.id = base.id;
this.EQ = base.EQ;
this.literal = base.literal;
},
set_id: function (_n) {
this._id = _n;
},
set_EQ: function (_n) {
this._EQ = _n;
},
set_literal: function (_n) {
this._literal = _n;
}
});
var and = std.class([Rule], {
constructor: function and(_options) {
var base = tools.merge({
lexpr: null,
AND: null,
rexpr: null
}, _options);
Rule.call(this, base);
this.lexpr = base.lexpr;
this.AND = base.AND;
this.rexpr = base.rexpr;
},
set_lexpr: function (_n) {
this._lexpr = _n;
},
set_AND: function (_n) {
this._AND = _n;
},
set_rexpr: function (_n) {
this._rexpr = _n;
}
});
var expr = std.class([Rule], {
constructor: function expr(_options) {
var base = tools.merge({}, _options);
Rule.call(this, base);
}
});
return {
// terminal
LEXEME: Lexeme,
// non terminal
string_literal: string_literal,
integer_literal: integer_literal,
id: id,
literal: literal,
eq: eq,
and: and,
expr: expr,
}
})();
var _result = {};
var LemonJS = function (_input) {
var parser = new Parser();
var lexer = new Lexer(_input);
var token;
while (token = lexer.next()) {
console.log("PARSE", token.lexeme);
parser.parse(parser["TOKEN_" + token.lexeme], token);
}
parser.parse();
return _result;
};
fs.mkdirSync("tests");
var test_and = LemonJS("abc == 1 and abc1 == 2 and (bbc == 5)");
fs.writeFileSync("tests/out_test_and.json", JSON.stringify(test_and, true, 3));
var test_address = LemonJS('abc == Address ["a", "b", "c"]');
fs.writeFileSync("tests/out_tree_address.json", JSON.stringify(test_address, true, 3));