@scalenc/nc-format
Version:
Library for handling TRUMPF NC file format.
233 lines • 11.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StatementReader = void 0;
const Expressions_1 = require("../models/Expressions");
const Assignment_1 = require("../models/Statements/Assignment");
const FlowControlInstruction_1 = require("../models/Statements/FlowControlInstruction");
const GCode_1 = require("../models/Statements/GCode");
const Goto_1 = require("../models/Statements/Goto");
const Instruction_1 = require("../models/Statements/Instruction");
const MCode_1 = require("../models/Statements/MCode");
const Constants_1 = require("./Constants");
const DeclarationReader_1 = require("./DeclarationReader");
const Errors_1 = require("./Errors");
const ExpressionReader_1 = require("./ExpressionReader");
const ParserException_1 = require("./ParserException");
const Token_1 = require("./Token");
class StatementReader {
parser;
expressionReader;
enableGCodeArguments = false;
enableStringInstructions = false;
constructor(parser) {
this.parser = parser;
this.expressionReader = new ExpressionReader_1.ExpressionReader(parser);
}
read() {
const statement = this.tryRead();
if (!statement) {
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.UNEXPECTED_LINE_OR_FILE_END);
}
return statement;
}
tryRead() {
if (Token_1.isLineOrFileEnd(this.parser.token)) {
return undefined;
}
if (Token_1.isGCode(this.parser.token)) {
return this.readGCode();
}
else if (Token_1.isMCode(this.parser.token)) {
return this.readMCode();
}
else if (Token_1.isGoto(this.parser.token)) {
return this.readGoto();
}
else if (Token_1.isDeclaration(this.parser.token)) {
return this.readDeclaration();
}
else if (Token_1.isFlowControlInstruction(this.parser.token)) {
return this.readFlowControlInstruction();
}
else {
return this.readAssignmentOrInstruction();
}
}
readGCode() {
this.parser.tryRead(); // Skip 'G'.
this.parser.assertNotLineOrFileEnd();
const id = this.parser.readIntegerNumber();
const args = this.enableGCodeArguments && Token_1.isOpeningFieldBrace(this.parser.token) ? this.readFieldBraceArguments() : undefined;
return new GCode_1.GCode(id, args);
}
readFieldBraceArguments() {
const args = [];
while (this.parser.tryRead()) {
// Skip '[', or ','
this.parser.assertNotLineOrFileEnd();
args.push(this.expressionReader.readExpression());
if (this.parser.token?.type !== Token_1.TokenType.SEPARATOR) {
break;
}
}
ParserException_1.ParserException.assert(Token_1.isCloseingFieldBrace(this.parser.token), this.parser, Errors_1.Errors.EXPECTED_CLOSING_FIELD_BRACE);
this.parser.tryRead(); // Skip ']'.
return args;
}
readMCode() {
this.parser.tryRead(); // Skip 'M'.
this.parser.assertNotLineOrFileEnd();
return new MCode_1.MCode(this.parser.readIntegerNumber());
}
readGoto() {
let direction = Goto_1.GotoDirection.SEARCH;
if (this.parser.token && this.parser.token.value.length !== Constants_1.Constants.GOTO.length) {
switch (this.parser.token.value[Constants_1.Constants.GOTO.length].toUpperCase()) {
case Constants_1.Constants.GOTO_START:
direction = Goto_1.GotoDirection.START;
break;
case Constants_1.Constants.GOTO_BACKWARD:
direction = Goto_1.GotoDirection.BACKWARD;
break;
case Constants_1.Constants.GOTO_FORWARD:
direction = Goto_1.GotoDirection.FORWARD;
break;
case Constants_1.Constants.GOTO_SEARCH_NO_ERRORS:
direction = Goto_1.GotoDirection.SEARCH_WITHOUT_ERROR;
break;
default:
ParserException_1.ParserException.fail(this.parser, Errors_1.Errors.EXPECTED_GOTO);
break;
}
}
this.parser.tryRead();
let target = undefined;
if (direction !== Goto_1.GotoDirection.START) {
this.parser.assertNotLineOrFileEnd();
target = this.expressionReader.readExpression();
}
return new Goto_1.Goto(direction, target);
}
readDeclaration() {
const declarationReader = new DeclarationReader_1.DeclarationReader(this.parser);
return declarationReader.readDeclaration();
}
readFlowControlInstruction() {
const name = this.parser.token?.value.toUpperCase();
this.parser.tryRead(); // Skip instruction keyword.
let type;
let expressions;
switch (name) {
case Constants_1.Constants.IF:
type = FlowControlInstruction_1.FlowControlInstructionType.IF;
expressions = [this.expressionReader.readExpression()];
break;
case Constants_1.Constants.ELSE:
type = FlowControlInstruction_1.FlowControlInstructionType.ELSE;
break;
case Constants_1.Constants.ENDIF:
type = FlowControlInstruction_1.FlowControlInstructionType.ENDIF;
break;
case Constants_1.Constants.WHILE:
type = FlowControlInstruction_1.FlowControlInstructionType.WHILE;
expressions = [this.expressionReader.readExpression()];
break;
case Constants_1.Constants.ENDWHILE:
type = FlowControlInstruction_1.FlowControlInstructionType.ENDWHILE;
break;
case Constants_1.Constants.REPEAT:
type = FlowControlInstruction_1.FlowControlInstructionType.REPEAT;
break;
case Constants_1.Constants.UNTIL:
type = FlowControlInstruction_1.FlowControlInstructionType.UNTIL;
expressions = [this.expressionReader.readExpression()];
break;
case Constants_1.Constants.LOOP:
type = FlowControlInstruction_1.FlowControlInstructionType.LOOP;
break;
case Constants_1.Constants.ENDLOOP:
type = FlowControlInstruction_1.FlowControlInstructionType.ENDLOOP;
break;
case Constants_1.Constants.FOR: {
type = FlowControlInstruction_1.FlowControlInstructionType.FOR;
const assignment = this.readAssignmentOrInstruction();
if (!(assignment instanceof Assignment_1.Assignment)) {
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.EXPECTED_ASSIGNMENT_BUT_INSTRUCTION);
}
if (!Token_1.isToKeyword(this.parser.token)) {
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.EXPECTED_TO_KEYWORD);
}
this.parser.tryRead(); // Skip 'TO'.
const expression = this.expressionReader.readExpression();
expressions = [new Expressions_1.Variable(assignment.variable), assignment.expression, expression];
break;
}
case Constants_1.Constants.ENDFOR:
type = FlowControlInstruction_1.FlowControlInstructionType.ENDFOR;
break;
default:
throw new Error(`Expected flow control instruction but found ${name}`);
}
return new FlowControlInstruction_1.FlowControlInstruction(type, expressions);
}
readAssignmentOrInstruction() {
const expression = this.expressionReader.readExpression();
if (expression instanceof Expressions_1.Variable) {
if (Token_1.isAssignmentOperator(this.parser.token)) {
return this.readExplicitAssignment(expression);
}
if (expression.fieldExpressions) {
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.UNEXPECTED_FIELD_BRACES);
}
if (expression.name.length === 1) {
return this.readInlineAssignment(expression.name);
}
if (Constants_1.Constants.DIGIT_CHARS.test(expression.name[1])) {
return this.splitInlineAssignment(expression.name);
}
return new Instruction_1.Instruction(expression.name);
}
if (expression instanceof Expressions_1.Function) {
return new Instruction_1.Instruction(expression.name, expression.args);
}
if (expression instanceof Expressions_1.BinaryOperation) {
return this.extractInlineAssignmentWithSign(expression);
}
if (this.enableStringInstructions && expression instanceof Expressions_1.String) {
return new Instruction_1.Instruction(`${Constants_1.Constants.STRING_SEPARATOR}${expression.value}${Constants_1.Constants.STRING_SEPARATOR}`);
}
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.EXPECTED_ASSIGNMENT_OR_INSTRUCTION_BUT_FOUND_EXPRESSION);
}
readExplicitAssignment(variable) {
this.parser.tryRead(); // Skip '='.
const expression = this.expressionReader.readExpression();
return new Assignment_1.Assignment(variable.name, variable.fieldExpressions, expression);
}
readInlineAssignment(name) {
const expression = this.expressionReader.readExpression();
return new Assignment_1.Assignment(name, undefined, expression);
}
splitInlineAssignment(name) {
return new Assignment_1.Assignment(name.substring(0, 1), undefined, new Expressions_1.Number(+name.substring(1), true));
}
extractInlineAssignmentWithSign(binaryOperation) {
// Note, there might be more complicated expressions which are not supported by this algorithm,
// e.g. X-1.2+3 which should read as X = -1.2+3, but is {{X - 1.2} + 3}. Thus, the left expression
// is no number but a binary '-' operation.
if (binaryOperation.operator === Expressions_1.BinaryOperator.ADD || binaryOperation.operator === Expressions_1.BinaryOperator.SUBTRACT) {
if (binaryOperation.leftExpression instanceof Expressions_1.Variable &&
!binaryOperation.leftExpression.fieldExpressions &&
binaryOperation.leftExpression.name.length === 1) {
if (binaryOperation.operator === Expressions_1.BinaryOperator.SUBTRACT) {
if (binaryOperation.rightExpression instanceof Expressions_1.Number) {
binaryOperation.rightExpression.value = -binaryOperation.rightExpression.value;
}
}
return new Assignment_1.Assignment(binaryOperation.leftExpression.name, undefined, binaryOperation.rightExpression);
}
}
throw new ParserException_1.ParserException(this.parser, Errors_1.Errors.EXPECTED_ASSIGNMENT_OR_INSTRUCTION_BUT_FOUND_EXPRESSION);
}
}
exports.StatementReader = StatementReader;
//# sourceMappingURL=StatementReader.js.map