UNPKG

@scalenc/nc-format

Version:

Library for handling TRUMPF NC file format.

211 lines 8.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = void 0; const Constants_1 = require("./Constants"); const Errors_1 = require("./Errors"); const ParserException_1 = require("./ParserException"); const Token_1 = require("./Token"); class Parser { input; index = 0; line = 1; token; enableLineComments = true; enableBraceComments = false; constructor(input) { this.input = input; } get isOk() { return this.index < this.input.length; } get char() { return this.input[this.index]; } get isAtLineEnd() { return this.char === Constants_1.Constants.CARRIAGE_RETURN || this.char === Constants_1.Constants.NEW_LINE; } get isNameChar() { return Constants_1.Constants.NAME_CHARS.test(this.char); } get isDigitChar() { return Constants_1.Constants.DIGIT_CHARS.test(this.char); } get isNumberChar() { return Constants_1.Constants.NUMBER_CHARS.test(this.char); } get isNumberConstantChar() { return this.char === Constants_1.Constants.NUMBER_CONSTANT_SEPARATOR; } get isStringChar() { return this.char === Constants_1.Constants.STRING_SEPARATOR; } get isArgumentSeparatorChar() { return this.char === Constants_1.Constants.ARGUMENT_SEPARATOR; } get isBraceChar() { return this.char === Constants_1.Constants.OPENING_BRACE || this.char === Constants_1.Constants.CLOSING_BRACE; } get isColonChar() { return this.char === Constants_1.Constants.COLON; } get isOperatorChar() { return Constants_1.Constants.OPERATOR_CHARS.includes(this.char); } get isFieldBraceChar() { return this.char === Constants_1.Constants.DEF_FIELD_BEGIN || this.char === Constants_1.Constants.DEF_FIELD_END; } assertNotLineOrFileEnd() { ParserException_1.ParserException.assert(!Token_1.isLineOrFileEnd(this.token), this, Errors_1.Errors.UNEXPECTED_LINE_OR_FILE_END); } readIntegerNumber() { const value = Token_1.tryGetNumberAsInteger(this.token); if (value === undefined) { throw new ParserException_1.ParserException(this, Errors_1.Errors.EXPECTED_INTEGER); } this.tryRead(); return value; } tryRead() { const whiteSpace = this.trySkipWhiteSpace(); if (!this.isOk) { this.token = undefined; } else if (this.isAtLineEnd) { this.token = { type: Token_1.TokenType.NEW_LINE, whiteSpace, value: this.readSingle() }; } else if (this.enableLineComments && this.char === Constants_1.Constants.COMMENT_CHAR) { this.token = { type: Token_1.TokenType.COMMENT, whiteSpace, value: this.readComment() }; } else if (this.enableBraceComments && this.char === Constants_1.Constants.OPENING_BRACE) { this.token = { type: Token_1.TokenType.COMMENT, whiteSpace, value: this.readBraceComment() }; } else if (this.isNameChar) { this.token = this.correctTokenTypeForNamedOperators({ type: Token_1.TokenType.IDENTIFIER, whiteSpace, value: this.readName() }); } else if (this.isNumberConstantChar) { this.token = { type: Token_1.TokenType.NUMBER, whiteSpace, value: this.readNumberConstant() }; } else if (this.isNumberChar) { this.token = { type: Token_1.TokenType.NUMBER, whiteSpace, value: this.readNumber() }; } else if (this.isStringChar) { this.token = { type: Token_1.TokenType.STRING, whiteSpace, value: this.readString() }; } else if (this.isArgumentSeparatorChar) { this.token = { type: Token_1.TokenType.SEPARATOR, whiteSpace, value: this.readSingle() }; } else if (this.isColonChar) { this.token = { type: Token_1.TokenType.COLON, whiteSpace, value: this.readSingle() }; } else if (this.isBraceChar) { this.token = { type: Token_1.TokenType.BRACE, whiteSpace, value: this.readSingle() }; } else if (this.isOperatorChar) { this.token = { type: Token_1.TokenType.OPERATOR, whiteSpace, value: this.readOperator() }; } else if (this.isFieldBraceChar) { this.token = { type: Token_1.TokenType.FIELD_BRACE, whiteSpace, value: this.readSingle() }; } else { throw new ParserException_1.ParserException(this, Errors_1.Errors.INVALID_CHARACTER.replace(/\{0\}/g, this.char)); } return !!this.token; } readComment() { return this.readWhile(() => !this.isAtLineEnd, 1); } readBraceComment() { const comment = this.readWhile(() => !this.isAtLineEnd && this.char != Constants_1.Constants.CLOSING_BRACE, 1); if (this.char === Constants_1.Constants.CLOSING_BRACE) { this.tryReadNextChar(); // Skip end of comment. this.trySkipWhiteSpace(); ParserException_1.ParserException.assert(this.isAtLineEnd, this, Errors_1.Errors.ADDTIONAL_CHARS_AFTER_BRACE_COMMENT); } return comment; } readName() { const i = this.index; return this.readWhile(() => this.isNameChar || (this.isDigitChar && !this.isSpecialName(i))); } isSpecialName(startIndex) { return ( // One-character names with subsequent digit are assignments, e.g. 'N100'. this.index - startIndex === 1 || // 'EX' with subsequent digit are exponents for numbers, e.g. '1EX3'. (this.index - startIndex === 2 && this.input.substring(startIndex, this.index).toUpperCase() === Constants_1.Constants.NUMBER_EXPONENT)); } readNumber() { let hasDot = this.char === '.'; return this.readWhile(() => { if (this.char === '.') { ParserException_1.ParserException.assert(!hasDot, this, Errors_1.Errors.TOO_MANY_DECIMAL_CHARS); hasDot = true; } return this.isNumberChar; }); } readNumberConstant() { const content = this.readWhile(() => !this.isAtLineEnd && !this.isNumberConstantChar, 1); ParserException_1.ParserException.assert(this.isOk && this.isNumberConstantChar, this, Errors_1.Errors.MISSING_STRING_END); this.tryReadNextChar(); // Skip end of number constant. return content; } readString() { const content = this.readWhile(() => !this.isAtLineEnd && !this.isStringChar, 1); ParserException_1.ParserException.assert(this.isOk && this.isStringChar, this, Errors_1.Errors.MISSING_STRING_END); this.tryReadNextChar(); // Skip end of string. return content; } readOperator() { let s = this.readSingle(); while (this.isOk && this.isOperatorChar && this.isValidOperator(s + this.char)) { s += this.char; this.tryReadNextChar(); } return s; } isValidOperator(s) { if (s.length === 2) { if (s[0] === Constants_1.Constants.LESS_OPERATOR_CHAR) { return s[1] === Constants_1.Constants.LESS_OPERATOR_CHAR || s[1] === Constants_1.Constants.EQUAL_OPERATOR_CHAR || s[1] === Constants_1.Constants.GREATER_OPERATOR_CHAR; } return (s[0] === Constants_1.Constants.GREATER_OPERATOR_CHAR || s[0] === Constants_1.Constants.EQUAL_OPERATOR_CHAR) && s[1] === Constants_1.Constants.EQUAL_OPERATOR_CHAR; } return s.length === 1; } trySkipWhiteSpace() { const isWhiteSpace = () => !this.isAtLineEnd && Constants_1.Constants.WHITE_SPACE_CHARS.test(this.char); return isWhiteSpace() ? this.readWhile(isWhiteSpace) : ''; } correctTokenTypeForNamedOperators(token) { if (Constants_1.Constants.NAMED_OPERATORS.includes(token.value.toUpperCase())) { token.type = Token_1.TokenType.OPERATOR; } return token; } readSingle() { const c = this.char; this.tryReadNextChar(); return c; } readWhile(predicate, skipFirst = 0) { const i = this.index + skipFirst; // eslint-disable-next-line no-empty while (this.tryReadNextChar() && predicate()) { } return this.input.substring(i, this.index); } tryReadNextChar() { if (this.isOk) { ++this.index; if (this.isAtLineEnd) { ++this.line; if (this.char === Constants_1.Constants.CARRIAGE_RETURN && this.input[this.index + 1] === Constants_1.Constants.NEW_LINE) { ++this.index; } } } return this.isOk; } } exports.Parser = Parser; //# sourceMappingURL=Parser.js.map