@jeefo/parser
Advanced tools
Comparing version 0.0.1 to 0.0.2
414
index.js
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : index.js | ||
* Created at : 2019-01-23 | ||
* Updated at : 2019-03-09 | ||
* Updated at : 2019-09-08 | ||
* Author : jeefo | ||
* Purpose : | ||
* Description : | ||
_._._._._._._._._._._._._._._._._._._._._.*/ | ||
* Reference : | ||
.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.*/ | ||
// ignore:start | ||
"use strict"; | ||
/* globals */ | ||
/* exported */ | ||
/* globals*/ | ||
/* exported*/ | ||
// ignore:end | ||
const State = require("./src/state"), | ||
assign = require("jeefo_utils/object/assign"), | ||
UnexpectedTokenException = require("./src/unexpected_token_exception"); | ||
const JeefoTokenizer = require("@jeefo/tokenizer"); | ||
const assign = require("@jeefo/utils/object/assign"); | ||
const for_each = require("@jeefo/utils/object/for_each"); | ||
const State = require("./src/state"); | ||
const I_AST_Node = require("./src/i_ast_node"); | ||
const AST_Node_Table = require("./src/ast_node_table"); | ||
const AST_Node_Definition = require("./src/ast_node_definition"); | ||
const UnexpectedTokenException = require("./src/unexpected_token_exception"); | ||
const TERMINATOR_PRECEDENCE = 0; | ||
const TERMINATOR_PRECEDENCE = 0; | ||
const object_define_property = Object.defineProperty; | ||
class JeefoParser { | ||
/** | ||
static get JeefoTokenizer () { return JeefoTokenizer; } | ||
static get I_AST_Node () { return I_AST_Node; } | ||
static get AST_Node_Table () { return AST_Node_Table; } | ||
static get AST_Node_Definition () { return AST_Node_Definition; } | ||
static get UnexpectedTokenException () { | ||
return UnexpectedTokenException; | ||
} | ||
/** | ||
* @Validators | ||
* @param: language (String) | ||
* @param: tokenizer (JeefoTokenizer) | ||
* @param: symbol_table (JeefoSymbolTable) | ||
*/ | ||
constructor (language, tokenizer, symbol_table) { | ||
this.language = language; | ||
this.tokenizer = tokenizer; | ||
this.symbol_table = symbol_table; | ||
* @param: language (String) | ||
* @param: tokenizer (JeefoTokenizer) | ||
* @param: ast_node_table (AST_Node_Table) | ||
*/ | ||
constructor (language, tokenizer, ast_node_table) { | ||
if (typeof language !== "string") { | ||
throw new TypeError("Invalid argument: language"); | ||
} | ||
if (! (tokenizer instanceof JeefoTokenizer)) { | ||
throw new TypeError("Invalid argument: tokenizer"); | ||
} | ||
if (! (ast_node_table instanceof AST_Node_Table)) { | ||
throw new TypeError("Invalid argument: ast_node_table"); | ||
} | ||
this.is_terminated = null; | ||
this.current_symbol = null; | ||
this.previous_symbols = null; | ||
this.language = language; | ||
this.tokenizer = tokenizer; | ||
this.ast_node_table = ast_node_table; | ||
this.next_token = null; | ||
this.next_symbol_definition = null; | ||
this.debug = false; | ||
this.prev_node = null; | ||
this.ending_index = 0; | ||
this.is_terminated = null; | ||
this.previous_nodes = null; | ||
this.next_token = null; | ||
this.next_node_definition = null; | ||
this.state = new State(); | ||
this.suffixes = []; | ||
this.context_stack = []; | ||
this.current_state = this.state.default; | ||
} | ||
prepare_next_symbol_definition () { | ||
this.next_token = this.tokenizer.get_next_token(); | ||
let onpreparation = null; | ||
object_define_property(this, "onpreparation", { | ||
get () { return onpreparation; }, | ||
set (value) { | ||
if (typeof value !== "function") { | ||
throw new TypeError( | ||
"Assigned onpreparation is not a function" | ||
); | ||
} | ||
onpreparation = value; | ||
} | ||
}); | ||
} | ||
if (this.next_token) { | ||
this.next_symbol_definition = this.symbol_table.get_symbol_definition(this.next_token, this); | ||
if (typeof this.onpreparation === "function") { | ||
look_ahead (throw_end_of_stream) { | ||
const { | ||
next_token : current_token, | ||
current_state : prev_state, | ||
next_node_definition : current_node_def, | ||
prev_node, previous_nodes | ||
} = this; | ||
this.tokenizer.streamer.cursor.save(); | ||
this.prev_node = null; | ||
this.current_state = null; | ||
this.previous_nodes = []; | ||
this.prepare_next_node_definition(throw_end_of_stream); | ||
const next_token = this.next_token; | ||
this.tokenizer.streamer.cursor.rollback(); | ||
this.prev_node = prev_node; | ||
this.next_token = current_token; | ||
this.current_state = prev_state; | ||
this.previous_nodes = previous_nodes; | ||
this.next_node_definition = current_node_def; | ||
return next_token; | ||
} | ||
prepare_next_node_definition (throw_end_of_stream) { | ||
this.next_token = this.tokenizer.get_next_token(); | ||
if (this.next_token) { | ||
// Only dev mode | ||
if (this.next_token) { | ||
this.next_token.id = this.next_token.id; | ||
this.next_token.priority = this.next_token.priority; | ||
} | ||
// Only dev mode | ||
this.next_node_definition = this.ast_node_table.find( | ||
this.next_token, this | ||
); | ||
if (this.onpreparation) { | ||
this.onpreparation(this); | ||
if (this.is_terminated || ! this.next_token) { | ||
this.next_node_definition = null; | ||
} | ||
} | ||
} else { | ||
this.next_symbol_definition = null; | ||
} | ||
} | ||
} else if (throw_end_of_stream) { | ||
this.throw_unexpected_end_of_stream(); | ||
} else { | ||
this.next_node_definition = null; | ||
} | ||
} | ||
prepare_next_state (state_name, throw_end_of_stream) { | ||
this.is_terminated = false; | ||
this.current_symbol = null; | ||
this.previous_symbols = []; | ||
this.prev_node = null; | ||
this.is_terminated = false; | ||
this.previous_nodes = []; | ||
this.next_node_definition = null; | ||
this.current_state = state_name ? this.state.get_value(state_name) : this.state.default; | ||
this.prepare_next_symbol_definition(); | ||
if (state_name) { | ||
this.current_state = this.state.get_value(state_name); | ||
} else { | ||
this.current_state = this.state.default; | ||
} | ||
this.prepare_next_node_definition(throw_end_of_stream); | ||
} | ||
if (throw_end_of_stream && this.next_token === null) { | ||
this.throw_unexpected_end_of_stream(); | ||
generate_next_node () { | ||
if (! this.next_node_definition) { | ||
this.throw_unexpected_token("AST_Node_Definition is not found"); | ||
} | ||
return this.next_node_definition.generate_new_node(this); | ||
} | ||
change_state (state_name) { | ||
this.current_state = this.state.get_value(state_name); | ||
this.next_symbol_definition = this.symbol_table.get_symbol_definition(this.next_token, this); | ||
change_state (state_name, set_prev_state, find_new_node = true) { | ||
if (set_prev_state !== undefined) { | ||
console.log(set_prev_state); | ||
throw new Error("Deprecated"); | ||
} | ||
if (set_prev_state) { | ||
this.prev_state = this.current_state; | ||
} | ||
this.current_state = this.state.get_value(state_name); | ||
if (find_new_node) { | ||
this.next_node_definition = this.ast_node_table.find( | ||
this.next_token, this | ||
); | ||
} | ||
} | ||
terminate (symbol) { | ||
if (symbol === undefined) { | ||
throw new Error("Undefined termination"); | ||
terminate (node) { | ||
if (node === undefined) { | ||
if (this.debug) { console.log(this); } | ||
throw new Error("argument must be AST_Node object."); | ||
} | ||
this.is_terminated = true; | ||
this.next_token = null; | ||
this.next_symbol_definition = null; | ||
assign(this.tokenizer.streamer.cursor, symbol.end); | ||
} | ||
this.is_terminated = true; | ||
this.next_token = null; | ||
this.next_node_definition = null; | ||
assign(this.tokenizer.streamer.cursor.position, node.end); | ||
} | ||
get_next_symbol (left_precedence) { | ||
if (typeof left_precedence !== "number") { | ||
throw new Error("Invalid left precedence"); | ||
} | ||
parse_next_node (left_precedence) { | ||
if (typeof left_precedence !== "number") { | ||
if (this.debug) { console.log(this); } | ||
throw new Error("Invalid left precedence"); | ||
} | ||
while (this.next_token) { | ||
if (this.next_symbol_definition === null) { | ||
this.throw_unexpected_token(); | ||
while (this.next_token) { | ||
if (this.next_node_definition === null) { | ||
if (this.throw_not_found) { | ||
this.throw_unexpected_token( | ||
"AST_Node_Definition is not found" | ||
); | ||
} | ||
break; | ||
} | ||
if (this.next_symbol_definition.precedence <= left_precedence) { | ||
if (this.next_node_definition.precedence <= left_precedence) { | ||
break; | ||
} | ||
const current_token = this.next_token; | ||
this.current_symbol = this.next_symbol_definition.generate_new_symbol(this); | ||
this.previous_symbols.push(this.current_symbol); | ||
this.ending_index = this.next_token.end.index; | ||
this.set_prev_node(this.generate_next_node()); | ||
if (current_token === this.next_token) { | ||
this.prepare_next_symbol_definition(); | ||
// Debug only | ||
if ([null, undefined].includes(this.current_state)) { | ||
this.throw_unexpected_token("Invalid current_state"); | ||
} | ||
} | ||
// Debug only | ||
return this.current_symbol; | ||
} | ||
if (this.next_token) { | ||
if (this.next_token.end.index === this.ending_index) { | ||
this.prepare_next_node_definition(); | ||
} else { | ||
this.next_node_definition = this.ast_node_table.find( | ||
this.next_token, this | ||
); | ||
} | ||
} | ||
} | ||
parse (script, tab_size) { | ||
const symbols = []; | ||
this.tokenizer.init(script, tab_size); | ||
return this.prev_node; | ||
} | ||
parse (script, tab_size) { | ||
const nodes = []; | ||
this.context_stack = []; | ||
this.tokenizer.init(script, tab_size); | ||
this.prepare_next_state(); | ||
while (this.next_token) { | ||
const symbol = this.get_next_symbol(TERMINATOR_PRECEDENCE); | ||
if (symbol) { | ||
symbols.push(symbol); | ||
while (this.next_token) { | ||
const node = this.parse_next_node(TERMINATOR_PRECEDENCE); | ||
if (node) { | ||
nodes.push(node); | ||
} else { | ||
this.throw_unexpected_token(); | ||
this.throw_unexpected_token("AST_Node is not found."); | ||
} | ||
this.prepare_next_state(); | ||
} | ||
} | ||
return symbols; | ||
} | ||
return nodes; | ||
} | ||
is_next_node (id) { | ||
if (this.next_node_definition) { | ||
return this.next_node_definition.id === id; | ||
} | ||
return false; | ||
} | ||
set_prev_node (prev_node) { | ||
this.prev_node = prev_node; | ||
this.previous_nodes.push(prev_node); | ||
} | ||
get_state_name (state) { | ||
const { values } = this.state; | ||
return Object.keys(values).find(state_name => { | ||
return values[state_name] === state; | ||
}); | ||
} | ||
get_state_value (state_name) { | ||
return this.state.get_value(state_name); | ||
} | ||
get_current_state_name () { | ||
return this.get_state_name(this.current_state); | ||
} | ||
end (node) { | ||
this.ending_index = node.end.index; | ||
} | ||
refine (state_name, input_node) { | ||
this.change_state(state_name, undefined); | ||
if (! this.next_node_definition) { | ||
this.throw_unexpected_token( | ||
`Unexpected state to refine: ${ state_name }`, | ||
input_node | ||
); | ||
} | ||
const Node = this.next_node_definition.Node; | ||
if (! this.next_node_definition.refine) { | ||
this.throw_unexpected_token( | ||
`refine method is not implemented in: ${ | ||
Node.prototype.constructor.name | ||
}`, input_node | ||
); | ||
} | ||
const node = new Node(); | ||
this.next_node_definition.refine(node, input_node, this); | ||
return node; | ||
} | ||
is_reserved_word (value) { | ||
return this.ast_node_table.reserved_words[value] !== undefined; | ||
} | ||
expect (expectation, condition) { | ||
if (! condition(this)) { | ||
this.throw_unexpected_token(`Expected ${ expectation } instead saw: ${ this.next_token.value }`); | ||
const { streamer } = this.tokenizer; | ||
this.throw_unexpected_token( | ||
`Expected ${ expectation } instead saw: ${ | ||
streamer.substring_from_token(this.next_token) | ||
}` | ||
); | ||
} | ||
} | ||
throw_unexpected_token (error_message) { | ||
throw new UnexpectedTokenException(this, error_message); | ||
} | ||
throw_unexpected_token (error_message, token) { | ||
if (token) { | ||
this.next_token = token; | ||
} | ||
if (this.debug) { console.log(this); } | ||
throw new UnexpectedTokenException(this, error_message); | ||
} | ||
throw_unexpected_end_of_stream () { | ||
throw new SyntaxError("Unexpected end of stream"); | ||
} | ||
throw_unexpected_refine (refining_node, error_node) { | ||
this.throw_unexpected_token( | ||
`Unexpected '${ error_node.constructor.name }' refine in: ${ | ||
refining_node.constructor.name | ||
}`, error_node | ||
); | ||
} | ||
throw_unexpected_end_of_stream () { | ||
if (this.debug) { console.log(this); } | ||
throw new SyntaxError("Unexpected end of stream"); | ||
} | ||
clone (name) { | ||
name = name || this.name; | ||
const tokenizer = new JeefoTokenizer(); | ||
const ast_node_table = new AST_Node_Table(); | ||
this.tokenizer.token_definitions.forEach(td => { | ||
tokenizer.register({ | ||
id : td.Token.prototype.id, | ||
priority : td.Token.prototype.priority, | ||
is : td.is, | ||
initialize : td.initialize, | ||
}); | ||
}); | ||
const { reserved_words, node_definitions } = this.ast_node_table; | ||
const defs = []; | ||
for_each(reserved_words, (word, node_def) => { | ||
const def = defs.find(d => d.node_def === node_def); | ||
if (def) { | ||
def.words.push(word); | ||
} else { | ||
defs.push({ words: [word], node_def }); | ||
} | ||
}); | ||
defs.forEach(def => { | ||
ast_node_table.register_reserved_words(def.words, def.node_def); | ||
}); | ||
ast_node_table.node_definitions = node_definitions.map(d => d.clone()); | ||
const clone = new JeefoParser(name, tokenizer, ast_node_table); | ||
Object.assign(clone.state.values, this.state.values); | ||
clone.state.default = this.state.default; | ||
if (this.onpreparation) { | ||
clone.onpreparation = this.onpreparation; | ||
} | ||
return clone; | ||
} | ||
} | ||
JeefoParser.prototype.onpreparation = null; | ||
module.exports = JeefoParser; |
{ | ||
"name": "@jeefo/parser", | ||
"version": "0.0.1", | ||
"description": "jeefo parser", | ||
"author": { | ||
"name": "je3f0o", | ||
"email": "je3f0o@gmail.com" | ||
}, | ||
"homepage": "https://github.com/je3f0o/jeefo_parser", | ||
"license": "MIT", | ||
"copyright": "2019", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "./node_modules/mocha/bin/mocha \"specs/**/*_specs.js\"" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/je3f0o/jeefo_parser.git" | ||
}, | ||
"keywords": [ | ||
"jeefo", | ||
"parser" | ||
], | ||
"devDependencies": { | ||
"expect.js": "^0.3.1", | ||
"mocha": "^3.5.0" | ||
}, | ||
"dependencies": { | ||
"jeefo_command": "^0.0.20", | ||
"jeefo_tokenizer": "^0.0.37", | ||
"jeefo_utils": "^0.0.5" | ||
} | ||
} | ||
"name": "@jeefo/parser", | ||
"version": "0.0.2", | ||
"description": "A library for parsing AST for any language.", | ||
"author": { | ||
"name": "je3f0o", | ||
"email": "je3f0o@gmail.com" | ||
}, | ||
"homepage": "https://github.com/je3f0o/jeefo_parser", | ||
"license": "MIT", | ||
"copyright": "2019", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "./node_modules/mocha/bin/mocha \"specs/**/*_specs.js\"", | ||
"publish": "npx @jeefo/publish" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/je3f0o/jeefo_parser.git" | ||
}, | ||
"keywords": [ | ||
"jeefo", | ||
"je3f0o", | ||
"parser" | ||
], | ||
"devDependencies": { | ||
"@jeefo/publish": "0.0.22" | ||
}, | ||
"dependencies": {} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30429
0
1
781
9
2
- Removedjeefo_command@^0.0.20
- Removedjeefo_tokenizer@^0.0.37
- Removedjeefo_utils@^0.0.5
- Removedjeefo_command@0.0.20(transitive)
- Removedjeefo_tokenizer@0.0.37(transitive)
- Removedjeefo_utils@0.0.5(transitive)