UNPKG

@gobstones/gobstones-parser

Version:
1,514 lines (1,508 loc) 189 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /* eslint-disable no-underscore-dangle */ /* A SourceReader represents the current position in a source file. * It keeps track of line and column numbers. * Methods are non-destructive. For example: * * let r = new SourceReader('foo.gbs', 'if\n(True)'); * * r.peek(); // ~~> 'i' * r = r.consumeCharacter(); // Note: returns a new file reader. * * r.peek(); // ~~> 'f' * r = r.consumeCharacter(); * * r.peek(); // ~~> '\n' * r = r.consumeCharacter('\n'); * * r.line(); // ~~> 2 */ class SourceReader { constructor(filename, string) { this._filename = filename; // Filename this._string = string; // Source of the current file this._index = 0; // Index in the current file this._line = 1; // Line in the current file this._column = 1; // Column in the current file this._regions = []; // Lexical (static) stack of regions } _clone() { const r = new SourceReader(this._filename, this._string); r._index = this._index; r._line = this._line; r._column = this._column; r._regions = this._regions; return r; } get filename() { return this._filename; } get line() { return this._line; } get column() { return this._column; } get region() { if (this._regions.length > 0) { return this._regions[0]; } else { return ''; } } /* Consume one character */ consumeCharacter() { const r = this._clone(); if (r.peek() === '\n') { r._line++; r._column = 1; } else { r._column++; } r._index++; return r; } /* Consume characters from the input, one per each character in the string * (the contents of the string are ignored). */ consumeString(string) { let r = this._clone(); // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const _ of string) { r = r.consumeCharacter(); } return r; } /* Returns the SourceReader after consuming an 'invisible' character. * Invisible characters affect the index but not the line or column. */ consumeInvisibleCharacter() { const r = this._clone(); r._index++; return r; } /* Consume 'invisible' characters from the input, one per each character * in the string */ consumeInvisibleString(string) { // eslint-disable-next-line @typescript-eslint/no-this-alias let r = this; // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const _ of string) { r = r.consumeInvisibleCharacter(); } return r; } /* Return true if the substring occurs at the current point. */ startsWith(sub) { const i = this._index; const j = this._index + sub.length; return j <= this._string.length && this._string.substring(i, j) === sub; } /* Return true if we have reached the end of the current file */ eof() { return this._index >= this._string.length; } /* Return the current character, assuming we have not reached EOF */ peek() { return this._string[this._index]; } /* Push a region to the stack of regions (non-destructively) */ beginRegion(region) { const r = this._clone(); r._regions = [region].concat(r._regions); return r; } /* Pop a region from the stack of regions (non-destructively) */ endRegion() { const r = this._clone(); if (r._regions.length > 0) { r._regions = r._regions.slice(1); } return r; } } /* Return a source reader that represents an unknown position */ const UnknownPosition = new SourceReader('(?)', ''); /* An instance of MultifileReader represents a scanner for reading * source code from a list of files. */ class MultifileReader { /* The 'input' parameter should be either: * (1) a string. e.g. 'program {}', or * (2) a map from filenames to strings, e.g. * { * 'foo.gbs': 'program { P() }', * 'bar.gbs': 'procedure P() {}', * } */ constructor(input) { if (typeof input === 'string') { input = { '(?)': input }; } this._filenames = Object.keys(input); this._filenames.sort(); this._input = input; this._index = 0; } /* Return true if there are more files */ moreFiles() { return this._index + 1 < this._filenames.length; } /* Advance to the next file */ nextFile() { this._index++; } /* Return a SourceReader for the current files */ readCurrentFile() { if (this._index < this._filenames.length) { const filename = this._filenames[this._index]; return new SourceReader(filename, this._input[filename]); } else { return new SourceReader('(?)', ''); } } } /* Token tags are constant symbols */ const T_EOF = Symbol.for('T_EOF'); // End of file const T_NUM = Symbol.for('T_NUM'); // Number const T_STRING = Symbol.for('T_STRING'); // String constant const T_UPPERID = Symbol.for('T_UPPERID'); // Uppercase identifier const T_LOWERID = Symbol.for('T_LOWERID'); // Lowercase identifier /* Keywords */ const T_PROGRAM = Symbol.for('T_PROGRAM'); const T_INTERACTIVE = Symbol.for('T_INTERACTIVE'); const T_PROCEDURE = Symbol.for('T_PROCEDURE'); const T_FUNCTION = Symbol.for('T_FUNCTION'); const T_RETURN = Symbol.for('T_RETURN'); const T_IF = Symbol.for('T_IF'); const T_THEN = Symbol.for('T_THEN'); const T_ELSEIF = Symbol.for('T_ELSEIF'); const T_ELSE = Symbol.for('T_ELSE'); const T_CHOOSE = Symbol.for('T_CHOOSE'); const T_WHEN = Symbol.for('T_WHEN'); const T_OTHERWISE = Symbol.for('T_OTHERWISE'); const T_MATCHING = Symbol.for('T_MATCHING'); const T_SELECT = Symbol.for('T_SELECT'); const T_ON = Symbol.for('T_ON'); const T_REPEAT = Symbol.for('T_REPEAT'); const T_FOREACH = Symbol.for('T_FOREACH'); const T_IN = Symbol.for('T_IN'); const T_WHILE = Symbol.for('T_WHILE'); const T_SWITCH = Symbol.for('T_SWITCH'); const T_TO = Symbol.for('T_TO'); const T_LET = Symbol.for('T_LET'); const T_NOT = Symbol.for('T_NOT'); const T_DIV = Symbol.for('T_DIV'); const T_MOD = Symbol.for('T_MOD'); const T_TYPE = Symbol.for('T_TYPE'); const T_IS = Symbol.for('T_IS'); const T_RECORD = Symbol.for('T_RECORD'); const T_VARIANT = Symbol.for('T_VARIANT'); const T_CASE = Symbol.for('T_CASE'); const T_FIELD = Symbol.for('T_FIELD'); const T_UNDERSCORE = Symbol.for('T_UNDERSCORE'); const T_TIMEOUT = Symbol.for('T_TIMEOUT'); /* Symbols */ const T_LPAREN = Symbol.for('T_LPAREN'); const T_RPAREN = Symbol.for('T_RPAREN'); const T_LBRACE = Symbol.for('T_LBRACE'); const T_RBRACE = Symbol.for('T_RBRACE'); const T_LBRACK = Symbol.for('T_LBRACK'); const T_RBRACK = Symbol.for('T_RBRACK'); const T_COMMA = Symbol.for('T_COMMA'); const T_SEMICOLON = Symbol.for('T_SEMICOLON'); const T_ELLIPSIS = Symbol.for('T_ELLIPSIS'); const T_RANGE = Symbol.for('T_RANGE'); const T_GETS = Symbol.for('T_GETS'); const T_PIPE = Symbol.for('T_PIPE'); const T_ARROW = Symbol.for('T_ARROW'); const T_ASSIGN = Symbol.for('T_ASSIGN'); const T_EQ = Symbol.for('T_EQ'); const T_NE = Symbol.for('T_NE'); const T_LE = Symbol.for('T_LE'); const T_GE = Symbol.for('T_GE'); const T_LT = Symbol.for('T_LT'); const T_GT = Symbol.for('T_GT'); const T_AND = Symbol.for('T_AND'); const T_OR = Symbol.for('T_OR'); const T_CONCAT = Symbol.for('T_CONCAT'); const T_PLUS = Symbol.for('T_PLUS'); const T_MINUS = Symbol.for('T_MINUS'); const T_TIMES = Symbol.for('T_TIMES'); const T_POW = Symbol.for('T_POW'); /* A token is given by: * - A token tag (e.g. T_LOWERID, T_NUM). * - Possibly, a value (e.g. 'nroBolitas', 8). * When the value is irrelevant, we provide null by convention. * - Two positions, representing its location in the source. */ class Token { constructor(tag, value, startPos, endPos) { this._tag = tag; this._value = value; this._startPos = startPos; this._endPos = endPos; } toString() { const _tag = this._tag; const tag = typeof _tag === 'symbol' ? Symbol.keyFor(_tag).substring(2) : _tag; switch (tag) { case 'NUM': case 'STRING': case 'UPPERID': case 'LOWERID': return tag + '("' + this._value.toString() + '")'; default: return tag; } } get tag() { return this._tag; } get value() { return this._value; } get startPos() { return this._startPos; } get endPos() { return this._endPos; } } /* eslint-disable camelcase */ const N_Main = Symbol.for('N_Main'); /* Definitions */ const N_DefProgram = Symbol.for('N_DefProgram'); const N_DefInteractiveProgram = Symbol.for('N_DefInteractiveProgram'); const N_DefProcedure = Symbol.for('N_DefProcedure'); const N_DefFunction = Symbol.for('N_DefFunction'); const N_DefType = Symbol.for('N_DefType'); /* Statements */ const N_StmtBlock = Symbol.for('N_StmtBlock'); const N_StmtReturn = Symbol.for('N_StmtReturn'); const N_StmtIf = Symbol.for('N_StmtIf'); const N_StmtRepeat = Symbol.for('N_StmtRepeat'); const N_StmtForeach = Symbol.for('N_StmtForeach'); const N_StmtWhile = Symbol.for('N_StmtWhile'); const N_StmtSwitch = Symbol.for('N_StmtSwitch'); const N_StmtAssignVariable = Symbol.for('N_StmtAssignVariable'); const N_StmtAssignTuple = Symbol.for('N_StmtAssignTuple'); const N_StmtProcedureCall = Symbol.for('N_StmtProcedureCall'); /* Patterns */ const N_PatternWildcard = Symbol.for('N_PatternWildcard'); const N_PatternVariable = Symbol.for('N_PatternVariable'); const N_PatternNumber = Symbol.for('N_PatternNumber'); const N_PatternStructure = Symbol.for('N_PatternStructure'); const N_PatternTuple = Symbol.for('N_PatternTuple'); const N_PatternTimeout = Symbol.for('N_PatternTimeout'); /* Expressions */ const N_ExprVariable = Symbol.for('N_ExprVariable'); const N_ExprConstantNumber = Symbol.for('N_ExprConstantNumber'); const N_ExprConstantString = Symbol.for('N_ExprConstantString'); const N_ExprChoose = Symbol.for('N_ExprChoose'); const N_ExprMatching = Symbol.for('N_ExprMatching'); const N_ExprList = Symbol.for('N_ExprList'); const N_ExprRange = Symbol.for('N_ExprRange'); const N_ExprTuple = Symbol.for('N_ExprTuple'); const N_ExprStructure = Symbol.for('N_ExprStructure'); const N_ExprStructureUpdate = Symbol.for('N_ExprStructureUpdate'); const N_ExprFunctionCall = Symbol.for('N_ExprFunctionCall'); /* SwitchBranch: pattern -> body */ const N_SwitchBranch = Symbol.for('N_SwitchBranch'); /* MatchingBranch: pattern -> body */ const N_MatchingBranch = Symbol.for('N_MatchingBranch'); /* FieldBinding: fieldName <- value */ const N_FieldBinding = Symbol.for('N_FieldBinding'); /* ConstructorDeclaration */ const N_ConstructorDeclaration = Symbol.for('N_ConstructorDeclaration'); /* Helper functions for the ASTNode toString method */ function indent(string) { const lines = []; for (const line of string.split('\n')) { lines.push(' ' + line); } return lines.join('\n'); } function showAST(node) { if (node === undefined) { return 'null'; } else if (node instanceof Array) { return '[\n' + showASTs(node).join(',\n') + '\n]'; } else if (node instanceof Token) { return node.toString(); } const tag = Symbol.keyFor(node.tag).substring(2); return tag + '(\n' + showASTs(node.children).join(',\n') + '\n)'; } function showASTs(nodes) { const res = []; for (const node of nodes) { res.push(indent(showAST(node))); } return res; } /** An instance of ASTNode represents a node of the abstract syntax tree. * - tag should be a node tag symbol. * - children should be (recursively) a possibly empty array of ASTNode's. * - startPos and endPos represent the starting and ending * position of the code fragment in the source code, to aid error * reporting. **/ class ASTNode { constructor(tag, children) { this._tag = tag; this._children = children; this._startPos = UnknownPosition; this._endPos = UnknownPosition; this._attributes = {}; /* Assert this invariant to protect against common mistakes. */ if (!(children instanceof Array)) { throw Error('The children of an ASTNode should be an array.'); } } toMulangLike() { return { tag: this._tag.toString().replace(/(^Symbol\(|\)$)/g, ''), contents: this._children.map((node) => { if (node === undefined) { return 'null'; } else if (node instanceof Array) { return new ASTNode(Symbol('?'), node).toMulangLike().contents; } else if (node instanceof ASTNode) { return node.toMulangLike(); } else if (node instanceof Token) { return node.toString(); } else { return '?'; } }) }; } toString() { return showAST(this); } get tag() { return this._tag; } get children() { return this._children; } set startPos(position) { this._startPos = position; } get startPos() { return this._startPos; } set endPos(position) { this._endPos = position; } get endPos() { return this._endPos; } get attributes() { return this._attributes; } set attributes(attributes) { this._attributes = attributes; } } /* Main */ class ASTMain extends ASTNode { constructor(definitions) { super(N_Main, definitions); } get definitions() { return this.children; } } /* Definitions */ class ASTDefProgram extends ASTNode { constructor(body) { super(N_DefProgram, [body]); } get body() { return this.children[0]; } } class ASTNodeWithBranches extends ASTNode { get branches() { return this.children; } } class ASTDefInteractiveProgram extends ASTNodeWithBranches { constructor(branches) { super(N_DefInteractiveProgram, branches); } get branches() { return this.children; } } class ASTDefProcedure extends ASTNode { constructor(name, parameters, body) { super(N_DefProcedure, [name, parameters, body]); } get name() { return this.children[0]; } get parameters() { return this.children[1]; } get body() { return this.children[2]; } } class ASTDefFunction extends ASTNode { constructor(name, parameters, body) { super(N_DefFunction, [name, parameters, body]); } get name() { return this.children[0]; } get parameters() { return this.children[1]; } get body() { return this.children[2]; } } class ASTDefType extends ASTNode { constructor(typeName, constructorDeclarations) { super(N_DefType, [typeName, constructorDeclarations]); } get typeName() { return this.children[0]; } get constructorDeclarations() { return this.children[1]; } } /* Statements */ class ASTStmtBlock extends ASTNode { constructor(statements) { super(N_StmtBlock, statements); } get statements() { return this.children; } } class ASTStmtReturn extends ASTNode { constructor(result) { super(N_StmtReturn, [result]); } get result() { return this.children[0]; } } class ASTStmtIf extends ASTNode { // Note: elseBlock may be null constructor(condition, thenBlock, elseBlock) { super(N_StmtIf, [condition, thenBlock, elseBlock]); } get condition() { return this.children[0]; } get thenBlock() { return this.children[1]; } get elseBlock() { return this.children[2]; } } class ASTStmtRepeat extends ASTNode { constructor(times, body) { super(N_StmtRepeat, [times, body]); } get times() { return this.children[0]; } get body() { return this.children[1]; } } class ASTNodeWithPattern extends ASTNode { get pattern() { return this.children[0]; } } class ASTStmtForeach extends ASTNodeWithPattern { constructor(pattern, range, body) { super(N_StmtForeach, [pattern, range, body]); } get pattern() { return this.children[0]; } get range() { return this.children[1]; } get body() { return this.children[2]; } } class ASTStmtWhile extends ASTNode { constructor(condition, body) { super(N_StmtWhile, [condition, body]); } get condition() { return this.children[0]; } get body() { return this.children[1]; } } class ASTStmtSwitch extends ASTNodeWithBranches { constructor(subject, branches) { super(N_StmtSwitch, [subject, branches]); } get subject() { return this.children[0]; } get branches() { return this.children[1]; } } class ASTSwitchBranch extends ASTNodeWithPattern { constructor(pattern, body) { super(N_SwitchBranch, [pattern, body]); } get pattern() { return this.children[0]; } get body() { return this.children[1]; } } class ASTMatchingBranch extends ASTNodeWithPattern { constructor(pattern, body) { super(N_MatchingBranch, [pattern, body]); } get pattern() { return this.children[0]; } get body() { return this.children[1]; } } class ASTStmtAssignVariable extends ASTNode { constructor(variable, value) { super(N_StmtAssignVariable, [variable, value]); } get variable() { return this.children[0]; } get value() { return this.children[1]; } } class ASTStmtAssignTuple extends ASTNode { constructor(variables, value) { super(N_StmtAssignTuple, [variables, value]); } get variables() { return this.children[0]; } get value() { return this.children[1]; } } class ASTStmtProcedureCall extends ASTNode { constructor(procedureName, args) { super(N_StmtProcedureCall, [procedureName, args]); } get procedureName() { return this.children[0]; } get args() { return this.children[1]; } } class ASTPatternWildcard extends ASTNode { constructor(statement) { super(N_PatternWildcard, []); } get boundVariables() { return []; } } class ASTPatternVariable extends ASTNode { constructor(variableName) { super(N_PatternVariable, [variableName]); } get variableName() { return this.children[0]; } get boundVariables() { return [this.children[0]]; } } class ASTPatternNumber extends ASTNode { constructor(number) { super(N_PatternNumber, [number]); } get number() { return this.children[0]; } get boundVariables() { return []; } } class ASTPatternStructure extends ASTNode { constructor(constructorName, parameters) { super(N_PatternStructure, [constructorName, parameters]); } get constructorName() { return this.children[0]; } get boundVariables() { return this.children[1]; } } class ASTPatternTuple extends ASTNode { constructor(parameters) { super(N_PatternTuple, parameters); } get boundVariables() { return this.children; } } class ASTPatternTimeout extends ASTNode { constructor(timeout) { super(N_PatternTimeout, [timeout]); } get boundVariables() { return []; } get timeout() { return parseInt(this.children[0].value, 10); } } class ASTExprVariable extends ASTNode { constructor(variableName) { super(N_ExprVariable, [variableName]); } get variableName() { return this.children[0]; } } class ASTExprConstantNumber extends ASTNode { constructor(number) { super(N_ExprConstantNumber, [number]); } get number() { return this.children[0]; } } class ASTExprConstantString extends ASTNode { constructor(string) { super(N_ExprConstantString, [string]); } get string() { return this.children[0]; } } class ASTExprChoose extends ASTNode { constructor(condition, trueExpr, falseExpr) { super(N_ExprChoose, [condition, trueExpr, falseExpr]); } get condition() { return this.children[0]; } get trueExpr() { return this.children[1]; } get falseExpr() { return this.children[2]; } } class ASTExprMatching extends ASTNodeWithBranches { constructor(subject, branches) { super(N_ExprMatching, [subject, branches]); } get subject() { return this.children[0]; } get branches() { return this.children[1]; } } class ASTExprList extends ASTNode { constructor(elements) { super(N_ExprList, elements); } get elements() { return this.children; } } class ASTExprRange extends ASTNode { // Note: second may be null constructor(first, second, last) { super(N_ExprRange, [first, second, last]); } get first() { return this.children[0]; } get second() { return this.children[1]; } get last() { return this.children[2]; } } class ASTExprTuple extends ASTNode { constructor(elements) { super(N_ExprTuple, elements); } get elements() { return this.children; } } class ASTExprStructure extends ASTNode { constructor(constructorName, fieldBindings) { super(N_ExprStructure, [constructorName, fieldBindings]); } get constructorName() { return this.children[0]; } get fieldBindings() { return this.children[1]; } fieldNames() { const names = []; for (const fieldBinding of this.fieldBindings) { names.push(fieldBinding.fieldName.value); } return names; } } class ASTExprStructureUpdate extends ASTNode { constructor(constructorName, original, fieldBindings) { super(N_ExprStructureUpdate, [constructorName, original, fieldBindings]); } get constructorName() { return this.children[0]; } get original() { return this.children[1]; } get fieldBindings() { return this.children[2]; } fieldNames() { const names = []; for (const fieldBinding of this.fieldBindings) { names.push(fieldBinding.fieldName.value); } return names; } } class ASTExprFunctionCall extends ASTNode { constructor(functionName, args) { super(N_ExprFunctionCall, [functionName, args]); } get functionName() { return this.children[0]; } get args() { return this.children[1]; } } class ASTFieldBinding extends ASTNode { constructor(fieldName, value) { super(N_FieldBinding, [fieldName, value]); } get fieldName() { return this.children[0]; } get value() { return this.children[1]; } } class ASTConstructorDeclaration extends ASTNode { constructor(constructorName, fieldNames) { super(N_ConstructorDeclaration, [constructorName, fieldNames]); } get constructorName() { return this.children[0]; } get fieldNames() { return this.children[1]; } } /* eslint-disable camelcase */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable quote-props */ /* istanbul ignore file */ const keyword$1 = (palabra) => 'la palabra clave "' + palabra + '"'; function pluralize$1(n, singular, plural) { if (n === 0) { return 'ningún ' + singular; } else if (n === 1) { return 'un ' + singular; } else { return n.toString() + ' ' + plural; } } // Only for typing purposes // eslint-disable-next-line @typescript-eslint/ban-types const toFunc$2 = (x) => x; function ordinalNumber(n) { const units = [ '', 'primer', 'segundo', 'tercer', 'cuarto', 'quinto', 'sexto', 'séptimo', 'octavo', 'noveno' ]; if (n >= 1 && n <= 9) { return units[n]; } else { return '#' + n.toString(); } } function describeType(type) { if (type.isInteger()) { return ['m', 'número', 'números']; } else if (type.isBoolean()) { return ['m', 'booleano', 'booleanos']; } else if (type.isColor()) { return ['m', 'color', 'colores']; } else if (type.isDirection()) { return ['f', 'dirección', 'direcciones']; } else if (type.isList() && type.contentType.isAny()) { return ['f', 'lista', 'listas']; } else if (type.isList()) { const description = describeType(type.contentType); if (description === undefined) { return undefined; } else { const plural = description[2]; return ['f', 'lista de ' + plural, 'listas de ' + plural]; } } else { return undefined; } } function describeTypeSingular(type) { const description = describeType(type); if (description === undefined) { return type.toString(); } else { const singular = description[1]; return singular; } } function typeAsNoun(type) { const description = describeType(type); if (description === undefined) { return 'un valor de tipo ' + type.toString(); } else { const gender = description[0]; const singular = description[1]; if (gender === 'm') { return 'un ' + singular; } else { return 'una ' + singular; } } } function typeAsQualifierSingular(type) { const description = describeType(type); if (description === undefined) { return 'de tipo ' + type.toString(); } else { const gender = description[0]; const singular = description[1]; if (gender === 'm') { return 'un ' + singular; } else { return 'una ' + singular; } } } function typeAsQualifierPlural(type) { const description = describeType(type); if (description === undefined) { return 'de tipo ' + type.toString(); } else { const gender = description[0]; const plural = description[2]; if (gender === 'm') { return plural; } else { return plural; } } } function listOfTypes(types) { const typeStrings = []; for (const type of types) { typeStrings.push(describeTypeSingular(type)); } return typeStrings.join(', '); } function openingDelimiterName(delimiter) { if (delimiter === '(' || delimiter === ')') { return 'un paréntesis abierto "("'; } else if (delimiter === '[' || delimiter === ']') { return 'un corchete abierto "["'; } else if (delimiter === '{' || delimiter === '}') { return 'una llave abierta "{"'; } else { return delimiter; } } function formatTypes(string, type1, type2) { let result = ''; for (let i = 0; i < string.length; i++) { if (string[i] === '%' && i + 1 < string.length) { if (string[i + 1] === '%') { result += '%'; i++; } else if (string[i + 1] === '1') { result += typeAsNoun(type1); i++; } else if (string[i + 1] === '2') { result += typeAsNoun(type2); i++; } else { result += '%'; } } else { result += string[i]; } } return result; } // eslint-disable-next-line @typescript-eslint/ban-types const LOCALE_ES = { /* Descriptions of syntactic constructions and tokens */ definition: 'una definición (de programa, función, procedimiento, o tipo)', pattern: 'un patrón (comodín "_", constructor aplicado a variables, o tupla)', statement: 'un comando', expression: 'una expresión', 'procedure call': 'una invocación a un procedimiento', 'field name': 'el nombre de un campo', T_EOF: 'el final del archivo', T_NUM: 'un número', T_STRING: 'una cadena (string)', T_UPPERID: 'un identificador con mayúsculas', T_LOWERID: 'un identificador con minúsculas', T_PROGRAM: keyword$1('program'), T_INTERACTIVE: keyword$1('interactive'), T_PROCEDURE: keyword$1('procedure'), T_FUNCTION: keyword$1('function'), T_RETURN: keyword$1('return'), T_IF: keyword$1('if'), T_THEN: keyword$1('then'), T_ELSE: keyword$1('else'), T_REPEAT: keyword$1('repeat'), T_FOREACH: keyword$1('foreach'), T_IN: keyword$1('in'), T_WHILE: keyword$1('while'), T_SWITCH: keyword$1('switch'), T_TO: keyword$1('to'), T_LET: keyword$1('let'), T_NOT: keyword$1('not'), T_DIV: keyword$1('div'), T_MOD: keyword$1('mod'), T_TYPE: keyword$1('type'), T_IS: keyword$1('is'), T_CHOOSE: keyword$1('choose'), T_WHEN: keyword$1('when'), T_OTHERWISE: keyword$1('otherwise'), T_MATCHING: keyword$1('matching'), T_SELECT: keyword$1('select'), T_ON: keyword$1('on'), T_RECORD: keyword$1('record'), T_VARIANT: keyword$1('variant'), T_CASE: keyword$1('case'), T_FIELD: keyword$1('field'), T_UNDERSCORE: 'un guión bajo ("_")', T_LPAREN: 'un paréntesis izquierdo ("(")', T_RPAREN: 'un paréntesis derecho (")")', T_LBRACE: 'una llave izquierda ("{")', T_RBRACE: 'una llave derecha ("}")', T_LBRACK: 'un corchete izquierdo ("[")', T_RBRACK: 'un corchete derecho ("]")', T_COMMA: 'una coma (",")', T_SEMICOLON: 'un punto y coma (";")', T_RANGE: 'un separador de rango ("..")', T_GETS: 'una flecha hacia la izquierda ("<-")', T_PIPE: 'una barra vertical ("|")', T_ARROW: 'una flecha ("->")', T_ASSIGN: 'un operador de asignación (":=")', T_EQ: 'una comparación por igualdad ("==")', T_NE: 'una comparación por desigualdad ("/=")', T_LE: 'un menor o igual ("<=")', T_GE: 'un mayor o igual (">=")', T_LT: 'un menor estricto ("<")', T_GT: 'un mayor estricto (">")', T_AND: 'el "y" lógico ("&&")', T_OR: 'el "o" lógico ("||")', T_CONCAT: 'el operador de concatenación de listas ("++")', T_PLUS: 'el operador de suma ("+")', T_MINUS: 'el operador de resta ("-")', T_TIMES: 'el operador de producto ("*")', T_POW: 'el operador de potencia ("^")', /* Local name categories */ LocalVariable: 'variable', LocalIndex: 'índice', LocalParameter: 'parámetro', /* Descriptions of value types */ V_Integer: 'un número', V_String: 'una cadena', V_Tuple: 'una tupla', V_List: 'una lista', V_Structure: 'una estructura', /* Lexer */ 'errmsg:unclosed-multiline-comment': 'El comentario se abre pero nunca se cierra.', 'errmsg:unclosed-string-constant': 'La comilla que abre no tiene una comilla que cierra correspondiente.', // eslint-disable-next-line max-len 'errmsg:numeric-constant-should-not-have-leading-zeroes': `Las constantes numéricas no se pueden escribir con ceros a la izquierda.`, // eslint-disable-next-line max-len 'errmsg:identifier-must-start-with-alphabetic-character': `Los identificadores deben empezar con un caracter alfabético (a...z,A...Z).`, 'errmsg:unknown-token': (symbol) => 'Símbolo desconocido en la entrada: "' + symbol + '".', 'warning:empty-pragma': 'Directiva pragma vacía.', 'warning:unknown-pragma': (pragmaName) => 'Directiva pragma desconocida: "' + pragmaName + '".', 'errmsg:unmatched-opening-delimiter': (delimiter) => 'Se encontró ' + openingDelimiterName(delimiter) + ' pero nunca se cierra.', 'errmsg:unmatched-closing-delimiter': (delimiter) => 'Se encontró un "' + delimiter + '" ' + 'pero no había ' + openingDelimiterName(delimiter) + '.', 'errmsg:unknown-language-option': (option) => 'Opción desconocida. "' + option + '".', /* Parser */ 'errmsg:empty-source': 'El programa está vacío.', 'errmsg:expected-but-found': (expected, found) => `Se esperaba ${expected}. Se encontró: ${found}.`, 'errmsg:pattern-number-cannot-be-negative-zero': 'El patrón numérico no puede ser "-0".', 'errmsg:return-tuple-cannot-be-empty': 'El return tiene que devolver algo.', 'errmsg:pattern-tuple-cannot-be-singleton': 'El patrón para una tupla no puede tener una sola componente. ' + 'Las tuplas tienen 0, 2, 3, o más componentes, pero no 1.', 'errmsg:assignment-tuple-cannot-be-singleton': 'La asignación a una tupla no puede constar de una sola componente. ' + 'Las tuplas tienen 0, 2, 3, o más componentes, pero no 1.', 'errmsg:operators-are-not-associative': (op1, op2) => 'La expresión usa ' + op1 + ' y ' + op2 + ', pero estos operadores no se pueden asociar. ' + 'Quizás faltan paréntesis.', 'errmsg:obsolete-tuple-assignment': 'Se esperaba un comando pero se encontró un paréntesis izquierdo. ' + 'Nota: la sintaxis de asignación de tuplas "(x1, ..., xN) := y" ' + 'está obsoleta. Usar "let (x1, ..., xN) := y".', /* Linter */ 'errmsg:program-already-defined': (pos1, pos2) => 'Ya había un programa definido en ' + pos1 + '.\n' + 'No se puede definir un programa en ' + pos2 + '.', 'errmsg:procedure-already-defined': (name, pos1, pos2) => 'El procedimiento "' + name + '" está definido dos veces: ' + 'en ' + pos1 + ' y en ' + pos2 + '.', 'errmsg:function-already-defined': (name, pos1, pos2) => 'La función "' + name + '" está definida dos veces: ' + 'en ' + pos1 + ' y en ' + pos2 + '.', 'errmsg:type-already-defined': (name, pos1, pos2) => `El tipo "${name}" está definido dos veces: en ${pos1} y en ${pos2}.`, 'errmsg:constructor-already-defined': (name, pos1, pos2) => 'El constructor "' + name + '" está definido dos veces: ' + 'en ' + pos1 + ' y en ' + pos2 + '.', 'errmsg:repeated-field-name': (constructorName, fieldName) => 'El campo "' + fieldName + '" no puede estar repetido ' + 'para el constructor "' + constructorName + '".', 'errmsg:function-and-field-cannot-have-the-same-name': (name, posFunction, posField) => 'El nombre "' + name + '" se usa ' + 'para una función en ' + posFunction + ' y ' + 'para un campo en ' + posField + '.', 'errmsg:source-should-have-a-program-definition': /* Note: the code may actually be completely empty, but * we avoid this technicality since the message could be * confusing. */ 'El código debe tener una definición de "program { ... }".', 'errmsg:procedure-should-not-have-return': (name) => `El procedimiento "${name}" no debería tener un comando "return".`, 'errmsg:function-should-have-return': (name) => 'La función "' + name + '" debería tener un comando "return".', 'errmsg:return-statement-not-allowed-here': 'El comando "return" solo puede aparecer como el último comando ' + 'de una función o como el último comando del programa.', 'errmsg:local-name-conflict': (name, oldCat, oldPos, newCat, newPos) => 'Conflicto de nombres: "' + name + '" se usa dos veces: ' + 'como ' + oldCat + ' en ' + oldPos + ', y ' + 'como ' + newCat + ' en ' + newPos + '.', 'errmsg:repeated-variable-in-tuple-assignment': (name) => `La variable "${name}" está repetida en la asignación de tuplas.`, 'errmsg:constructor-used-as-procedure': (name, type) => 'El procedimiento "' + name + '" no está definido. ' + 'El nombre "' + name + '" es el nombre de un constructor ' + 'del tipo "' + type + '".', 'errmsg:undefined-procedure': (name) => 'El procedimiento "' + name + '" no está definido.', 'errmsg:undefined-function': (name) => 'La función "' + name + '" no está definida.', 'errmsg:procedure-arity-mismatch': (name, expected, received) => '"El procedimiento "' + name + '" espera recibir ' + toFunc$2(LOCALE_ES['<n>-parameters'])(expected) + ' pero se lo invoca con ' + toFunc$2(LOCALE_ES['<n>-arguments'])(received) + '.', 'errmsg:function-arity-mismatch': (name, expected, received) => 'La función "' + name + '" espera recibir ' + toFunc$2(LOCALE_ES['<n>-parameters'])(expected) + ' pero se la invoca con ' + toFunc$2(LOCALE_ES['<n>-arguments'])(received) + '.', 'errmsg:structure-pattern-arity-mismatch': (name, expected, received) => 'El constructor "' + name + '" tiene ' + toFunc$2(LOCALE_ES['<n>-fields'])(expected) + ' pero el patrón tiene ' + toFunc$2(LOCALE_ES['<n>-parameters'])(received) + '.', 'errmsg:type-used-as-constructor'(name, constructorNames) { let msg; if (constructorNames.length === 0) { msg = '(no tiene constructores).'; } else if (constructorNames.length === 1) { msg = '(tiene un constructor: ' + constructorNames[0] + ').'; } else { msg = '(sus constructores son: ' + constructorNames.join(', ') + ').'; } return ('El constructor "' + name + '" no está definido. ' + 'El nombre "' + name + '" es el nombre de un tipo ' + msg); }, 'errmsg:procedure-used-as-constructor': (name) => 'El constructor "' + name + '" no está definido. ' + 'El nombre "' + name + '" es el nombre de un procedimiento.', 'errmsg:undeclared-constructor': (name) => 'El constructor "' + name + '" no está definido.', 'errmsg:wildcard-pattern-should-be-last': 'El comodín "_" debe estar en la última rama.', 'errmsg:variable-pattern-should-be-last': (name) => 'El patrón variable "' + name + '" tiene debe estar en la última rama.', 'errmsg:numeric-pattern-repeats-number': (number) => 'Hay dos ramas distintas para el número "' + number + '".', 'errmsg:structure-pattern-repeats-constructor': (name) => 'Hay dos ramas distintas para el constructor "' + name + '".', 'errmsg:structure-pattern-repeats-tuple-arity': (arity) => 'Hay dos ramas distintas para las tuplas de ' + arity.toString() + ' componentes.', 'errmsg:structure-pattern-repeats-timeout': 'Hay dos ramas distintas para el TIMEOUT.', 'errmsg:pattern-does-not-match-type': (expectedType, patternType) => 'Los patrones tienen que ser todos del mismo tipo. ' + 'El patrón debería ser de tipo ' + expectedType + 'pero es de tipo ' + patternType + '.', 'errmsg:patterns-in-interactive-program-must-be-events': 'Los patrones de un "interactive program" deben ser eventos.', 'errmsg:patterns-in-interactive-program-cannot-be-variables': 'El patrón no puede ser una variable.', 'errmsg:patterns-in-switch-must-not-be-events': 'El patrón no puede ser un evento.', 'errmsg:structure-construction-repeated-field': (constructorName, fieldName) => 'El campo "' + fieldName + '" está repetido en ' + 'la instanciación del constructor "' + constructorName + '".', 'errmsg:structure-construction-invalid-field': (constructorName, fieldName) => 'El campo "' + fieldName + '" no es un campo válido ' + 'para el constructor "' + constructorName + '".', 'errmsg:structure-construction-missing-field': (constructorName, fieldName) => 'Falta darle valor al campo "' + fieldName + '" ' + 'del constructor "' + constructorName + '".', 'errmsg:structure-construction-cannot-be-an-event': (constructorName) => 'El constructor "' + constructorName + '" corresponde a un ' + 'evento, y solamente se puede manejar implícitamente ' + 'en un programa interactivo (el usuario no puede construir ' + 'instancias).', 'errmsg:forbidden-extension-destructuring-foreach': 'El índice de la repetición indexada debe ser un identificador.', ['errmsg:forbidden-extension-allow-recursion']: (cycle) => { const msg = []; for (const call of cycle) { msg.push(' ' + call.caller + ' llama a ' + call.callee + ' (' + call.location.startPos.filename.toString() + ':' + call.location.startPos.line.toString() + ':' + call.location.startPos.column.toString() + ')'); } return ('La recursión está deshabilitada. ' + 'Hay un ciclo en las invocaciones:\n' + msg.join('\n')); }, 'errmsg:patterns-in-foreach-must-not-be-events': 'El patrón de un foreach no puede ser un evento.', /* Runtime errors (virtual machine) */ 'errmsg:ellipsis': 'El programa todavía no está completo.', 'errmsg:undefined-variable': (variableName) => 'La variable "' + variableName + '" no está definida.', 'errmsg:too-few-arguments': (routineName) => 'Faltan argumentos para "' + routineName + '".', 'errmsg:expected-structure-but-got': (constructorName, valueTag) => 'Se esperaba una estructura construida ' + 'con el constructor "' + constructorName + '", ' + 'pero se recibió ' + valueTag + '.', 'errmsg:expected-constructor-but-got': (constructorNameExpected, constructorNameReceived) => 'Se esperaba una estructura construida ' + 'con el constructor "' + constructorNameExpected + '", ' + 'pero el constructor recibido es ' + constructorNameReceived + '".', 'errmsg:incompatible-types-on-assignment': (variableName, oldType, newType) => 'La variable "' + variableName + '" ' + 'contenía ' + typeAsNoun(oldType) + ', ' + 'no se le puede asignar ' + typeAsNoun(newType) + '".', 'errmsg:incompatible-types-on-list-creation': (index, oldType, newType) => 'Todos los elementos de una lista deben ser del mismo tipo. ' + 'Los elementos son ' + typeAsQualifierPlural(oldType) + ', ' + 'pero el elemento en la posición ' + index.toString() + ' ' + 'es ' + typeAsQualifierSingular(newType) + '.', 'errmsg:incompatible-types-on-structure-update': (fieldName, oldType, newType) => 'El campo "' + fieldName + '" es ' + typeAsQualifierSingular(oldType) + '. ' + 'No se lo puede actualizar con ' + typeAsNoun(newType) + '.', 'errmsg:expected-tuple-value-but-got': (receivedType) => 'Se esperaba una tupla pero se recibió ' + typeAsNoun(receivedType) + '.', 'errmsg:tuple-component-out-of-bounds': (size, index) => 'Índice fuera de rango. ' + 'La tupla es de tamaño ' + size.toString() + ' y ' + 'el índice es ' + index.toString() + '.', 'errmsg:expected-structure-value-but-got': (receivedType) => 'Se esperaba una estructura pero se recibió ' + typeAsNoun(receivedType) + '.', 'errmsg:structure-field-not-present': (fieldNames, missingFieldName) => 'La estructura no tiene un campo "' + missingFieldName + '". ' + 'Los campos son: [' + fieldNames.join(', ') + '].', 'errmsg:primitive-does-not-exist': (primitiveName) => `La operación primitiva "${primitiveName}" no existe o no está disponible.`, 'errmsg:primitive-arity-mismatch': (name, expected, received) => 'La operación "' + name + '" espera recibir ' + toFunc$2(LOCALE_ES['<n>-parameters'])(expected) + ' pero se la invoca con ' + toFunc$2(LOCALE_ES['<n>-arguments'])(received) + '.', 'errmsg:primitive-argument-type-mismatch'(name, parameterIndex, numArgs, expectedType, receivedType) { let msg = 'El '; if (numArgs > 1) { msg += ordinalNumber(parameterIndex) + ' '; } msg += 'parámetro '; msg += 'de "' + name + '" '; msg += 'debería ser ' + typeAsQualifierSingular(expectedType) + ' '; msg += 'pero es ' + typeAsQualifierSingular(receivedType) + '.'; return msg; }, 'errmsg:expected-value-of-type-but-got': (expectedType, receivedType) => 'Se esperaba ' + typeAsNoun(expectedType) + ' ' + 'pero se recibió ' + typeAsNoun(receivedType) + '.', 'errmsg:expected-value-of-some-type-but-got': (expectedTypes, receivedType) => 'Se esperaba un valor de alguno de los siguientes tipos: ' + listOfTypes(expectedTypes) + '. ' + 'Pero se recibió ' + typeAsNoun(receivedType) + '.', 'errmsg:expected-values-to-have-compatible-types': (type1, type2) => 'Los tipos de las expresiones no coinciden: ' + 'la primera es ' + typeAsQualifierSingular(type1) + ' ' + 'y la segunda es ' + typeAsQualifierSingular(type2) + '.', 'errmsg:switch-does-not-match': 'El valor analizado no coincide con ninguna de las ramas del switch.', 'errmsg:foreach-pattern-does-not-match': 'El elemento no coincide con el patrón esperado por el foreach.', 'errmsg:cannot-divide-by-zero': 'No se puede dividir por cero.', 'errmsg:negative-exponent': 'El exponente de la potencia no puede ser negativo.', 'errmsg:list-cannot-be-empty': 'La lista no puede ser vacía.', 'errmsg:timeout': (millisecs) => 'La ejecución del programa demoró más de ' + millisecs.toString() + 'ms.', /* Typecheck */ 'errmsg:typecheck-failed': (errorMessage, type1, type2) => formatTypes(errorMessage, type1, type2), /* Board operations */ 'errmsg:cannot-move-to': (dirName) => 'No se puede mover hacia la dirección ' + dirName + ': cae afuera del tablero.', 'errmsg:cannot-remove-stone': (dirName) => 'No se puede sacar una bolita de color ' + dirName + ': no hay bolitas de ese color.', /* Runtime */ 'TYPE:Integer': 'Number', 'TYPE:String': 'String', 'TYPE:Tuple': '', 'TYPE:List': 'List', 'TYPE:Event': 'Event', 'CONS:INIT': 'INIT', 'CONS:TIMEOUT': 'TIMEOUT', 'TYPE:Bool': 'Bool', 'CONS:False': 'False', 'CONS:True': 'True', 'TYPE:Color': 'Color', 'CONS:Color0': 'Azul', 'CONS:Color1': 'Negro', 'CONS:Color2': 'Rojo', 'CONS:Color3': 'Verde', 'TYPE:Dir': 'Dir', 'CONS:Dir0': 'Norte', 'CONS:Dir1': 'Este', 'CONS:Dir2': 'Sur', 'CONS:Dir3': 'Oeste', 'PRIM:TypeCheck': 'TypeCheck', 'PRIM:BOOM': 'BOOM', 'PRIM:boom': 'boom', 'PRIM:PutStone': 'Poner', 'PRIM:RemoveStone': 'Sacar', 'PRIM:Move': 'Mover', 'PRIM:GoToEdge': 'IrAlBorde', 'PRIM:EmptyBoardContents': 'VaciarTablero', 'PRIM:numStones': 'nroBolitas', 'PRIM:anyStones': 'hayBolitas', 'PRIM:canMove': 'puedeMover', 'PRIM:next': 'siguiente', 'PRIM:prev': 'previo', 'PRIM:opposite': 'opuesto', 'PRIM:minBool': 'minBool', 'PRIM:maxBool': 'maxBool', 'PRIM:minColor': 'minColor', 'PRIM:maxColor': 'maxColor', 'PRIM:minDir': 'minDir', 'PRIM:maxDir': 'maxDir', 'PRIM:isEmpty': 'esVacía', 'PRIM:head': 'primero', 'PRIM:tail': 'sinElPrimero', 'PRIM:oldTail': 'resto', 'PRIM:init': 'comienzo', 'PRIM:last': 'último', /* Helpers */ '<alternative>': (strings) => 'alguna de las siguientes alternativas:\n' + strings.map((s) => ' ' + s).join('\n'), '<position>': (filename, line, column) => filename + ':' + line.toString() + ':' + column.toString(), '<n>-parameters': (n) => pluralize$1(n, 'parámetro', 'parámetros'), '<n>-arguments': (n) => pluralize$1(n, 'argumento', 'argumentos'), '<n>-fields': (n) => pluralize$1(n, 'campo', 'campos'), '<pattern-type>'(patternType) { if (patternType === 'Event') { return 'evento del programa interactivo'; } else if (patternType.substring(0, 7) === '_TUPLE_') { return 'tupla de ' + patternType.substring(7) + ' componentes'; } else { return patternType; } } }; const LOCALE_EN = {}; for (const key in LOCALE_ES) { LOCALE_EN[key] = LOCALE_ES[key]; } LOCALE_EN['TYPE:Color'] = 'Color'; LOCALE_EN['CONS:Color0'] = 'Blue'; LOCALE_EN['CONS:Color1'] = 'Black'; LOCALE_EN['CONS:Color2'] = 'Red'; LOCALE_EN['CONS:Color3'] = 'Green'; LOCALE_EN['TYPE:Dir'] = 'Dir'; LOCALE_EN['CONS:Dir0'] = 'North'; LOCALE_EN['CONS:Dir1'] = 'East'; LOCALE_EN['CONS:Dir2'] = 'South'; LOCALE_EN['CONS:Dir3'] = 'West'; LOCALE_EN['PRIM:PutStone'] = 'Drop'; LOCALE_EN['PRIM:RemoveStone'] = 'Grab'; LOCALE_