hispano-lang 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/evaluator.js +53 -60
- package/dist/parser.js +112 -0
- package/dist/tokenizer.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -341,6 +341,41 @@ variable duplicar = funcion(x) {
|
|
|
341
341
|
mostrar duplicar(5) // 10
|
|
342
342
|
```
|
|
343
343
|
|
|
344
|
+
#### Funciones Flecha
|
|
345
|
+
|
|
346
|
+
Sintaxis concisa para funciones anónimas:
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
// Un parámetro (sin paréntesis)
|
|
350
|
+
variable doble = x => x * 2
|
|
351
|
+
|
|
352
|
+
// Múltiples parámetros
|
|
353
|
+
variable suma = (a, b) => a + b
|
|
354
|
+
|
|
355
|
+
// Sin parámetros
|
|
356
|
+
variable saludar = () => "Hola mundo"
|
|
357
|
+
|
|
358
|
+
// Con bloque de código
|
|
359
|
+
variable factorial = n => {
|
|
360
|
+
si (n <= 1) { retornar 1 }
|
|
361
|
+
retornar n * factorial(n - 1)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
mostrar doble(5) // 10
|
|
365
|
+
mostrar suma(3, 4) // 7
|
|
366
|
+
mostrar factorial(5) // 120
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Funciones flecha son ideales para callbacks:
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
variable numeros = [1, 2, 3, 4, 5]
|
|
373
|
+
|
|
374
|
+
numeros.mapear(x => x * 2) // [2, 4, 6, 8, 10]
|
|
375
|
+
numeros.filtrar(x => x > 2) // [3, 4, 5]
|
|
376
|
+
numeros.reducir((a, b) => a + b, 0) // 15
|
|
377
|
+
```
|
|
378
|
+
|
|
344
379
|
#### Funciones como Parámetros
|
|
345
380
|
|
|
346
381
|
```
|
package/dist/evaluator.js
CHANGED
|
@@ -23,7 +23,7 @@ class Evaluator {
|
|
|
23
23
|
this.execute(statement);
|
|
24
24
|
}
|
|
25
25
|
} catch (error) {
|
|
26
|
-
throw new Error(
|
|
26
|
+
throw new Error(error.message);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
return this.output;
|
|
@@ -135,7 +135,6 @@ class Evaluator {
|
|
|
135
135
|
const value = this.evaluateExpression(statement.expression);
|
|
136
136
|
const output = this.stringify(value);
|
|
137
137
|
this.output.push(output);
|
|
138
|
-
console.log(output);
|
|
139
138
|
}
|
|
140
139
|
|
|
141
140
|
/**
|
|
@@ -307,6 +306,28 @@ class Evaluator {
|
|
|
307
306
|
}
|
|
308
307
|
}
|
|
309
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Executes a function body (handles both block and arrow expression bodies)
|
|
311
|
+
* @param {Object} func - Function object with body and isArrowExpression flag
|
|
312
|
+
* @returns {any} Result of the function execution
|
|
313
|
+
*/
|
|
314
|
+
executeFunctionBody(func) {
|
|
315
|
+
if (func.isArrowExpression) {
|
|
316
|
+
return this.evaluateExpression(func.body);
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
for (const statement of func.body) {
|
|
320
|
+
this.execute(statement);
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
} catch (returnValue) {
|
|
324
|
+
if (returnValue instanceof ReturnException) {
|
|
325
|
+
return returnValue.value;
|
|
326
|
+
}
|
|
327
|
+
throw returnValue;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
310
331
|
/**
|
|
311
332
|
* Executes an expression statement
|
|
312
333
|
* @param {Object} statement - Expression statement
|
|
@@ -339,6 +360,15 @@ class Evaluator {
|
|
|
339
360
|
body: expression.body,
|
|
340
361
|
};
|
|
341
362
|
|
|
363
|
+
case "ArrowFunction":
|
|
364
|
+
return {
|
|
365
|
+
type: "Function",
|
|
366
|
+
name: null,
|
|
367
|
+
parameters: expression.parameters,
|
|
368
|
+
body: expression.body,
|
|
369
|
+
isArrowExpression: expression.isExpression,
|
|
370
|
+
};
|
|
371
|
+
|
|
342
372
|
case "Assign":
|
|
343
373
|
const value = this.evaluateExpression(expression.value);
|
|
344
374
|
this.environment.assign(expression.name, value);
|
|
@@ -622,6 +652,10 @@ class Evaluator {
|
|
|
622
652
|
const previous = this.environment;
|
|
623
653
|
try {
|
|
624
654
|
this.environment = environment;
|
|
655
|
+
// Arrow functions with expression body return the expression directly
|
|
656
|
+
if (callee.isArrowExpression) {
|
|
657
|
+
return this.evaluateExpression(callee.body);
|
|
658
|
+
}
|
|
625
659
|
this.executeBlock(callee.body);
|
|
626
660
|
return null;
|
|
627
661
|
} catch (returnValue) {
|
|
@@ -856,7 +890,7 @@ class Evaluator {
|
|
|
856
890
|
const previousEnv = this.environment;
|
|
857
891
|
this.environment = callbackEnv;
|
|
858
892
|
try {
|
|
859
|
-
this.
|
|
893
|
+
this.executeFunctionBody(callback);
|
|
860
894
|
} finally {
|
|
861
895
|
this.environment = previousEnv;
|
|
862
896
|
}
|
|
@@ -884,14 +918,9 @@ class Evaluator {
|
|
|
884
918
|
const prevEnv = this.environment;
|
|
885
919
|
this.environment = filterEnv;
|
|
886
920
|
try {
|
|
887
|
-
this.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
if (this.isTruthy(returnValue.value)) {
|
|
891
|
-
filteredArray.push(array[i]);
|
|
892
|
-
}
|
|
893
|
-
} else {
|
|
894
|
-
throw returnValue;
|
|
921
|
+
const result = this.executeFunctionBody(filterCallback);
|
|
922
|
+
if (this.isTruthy(result)) {
|
|
923
|
+
filteredArray.push(array[i]);
|
|
895
924
|
}
|
|
896
925
|
} finally {
|
|
897
926
|
this.environment = prevEnv;
|
|
@@ -920,14 +949,8 @@ class Evaluator {
|
|
|
920
949
|
const prevEnv = this.environment;
|
|
921
950
|
this.environment = mapEnv;
|
|
922
951
|
try {
|
|
923
|
-
this.
|
|
924
|
-
mappedArray.push(
|
|
925
|
-
} catch (returnValue) {
|
|
926
|
-
if (returnValue instanceof ReturnException) {
|
|
927
|
-
mappedArray.push(returnValue.value);
|
|
928
|
-
} else {
|
|
929
|
-
throw returnValue;
|
|
930
|
-
}
|
|
952
|
+
const result = this.executeFunctionBody(mapCallback);
|
|
953
|
+
mappedArray.push(result);
|
|
931
954
|
} finally {
|
|
932
955
|
this.environment = prevEnv;
|
|
933
956
|
}
|
|
@@ -962,13 +985,7 @@ class Evaluator {
|
|
|
962
985
|
const prevEnv = this.environment;
|
|
963
986
|
this.environment = reduceEnv;
|
|
964
987
|
try {
|
|
965
|
-
this.
|
|
966
|
-
} catch (returnValue) {
|
|
967
|
-
if (returnValue instanceof ReturnException) {
|
|
968
|
-
accumulator = returnValue.value;
|
|
969
|
-
} else {
|
|
970
|
-
throw returnValue;
|
|
971
|
-
}
|
|
988
|
+
accumulator = this.executeFunctionBody(reduceCallback);
|
|
972
989
|
} finally {
|
|
973
990
|
this.environment = prevEnv;
|
|
974
991
|
}
|
|
@@ -1001,13 +1018,7 @@ class Evaluator {
|
|
|
1001
1018
|
const prevEnv = this.environment;
|
|
1002
1019
|
this.environment = sortEnv;
|
|
1003
1020
|
try {
|
|
1004
|
-
this.
|
|
1005
|
-
return 0;
|
|
1006
|
-
} catch (returnValue) {
|
|
1007
|
-
if (returnValue instanceof ReturnException) {
|
|
1008
|
-
return returnValue.value;
|
|
1009
|
-
}
|
|
1010
|
-
throw returnValue;
|
|
1021
|
+
return this.executeFunctionBody(sortCallback) || 0;
|
|
1011
1022
|
} finally {
|
|
1012
1023
|
this.environment = prevEnv;
|
|
1013
1024
|
}
|
|
@@ -1040,15 +1051,9 @@ class Evaluator {
|
|
|
1040
1051
|
const prevEnv = this.environment;
|
|
1041
1052
|
this.environment = findEnv;
|
|
1042
1053
|
try {
|
|
1043
|
-
this.
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
if (this.isTruthy(returnValue.value)) {
|
|
1047
|
-
this.environment = prevEnv;
|
|
1048
|
-
return array[i];
|
|
1049
|
-
}
|
|
1050
|
-
} else {
|
|
1051
|
-
throw returnValue;
|
|
1054
|
+
const result = this.executeFunctionBody(findCallback);
|
|
1055
|
+
if (this.isTruthy(result)) {
|
|
1056
|
+
return array[i];
|
|
1052
1057
|
}
|
|
1053
1058
|
} finally {
|
|
1054
1059
|
this.environment = prevEnv;
|
|
@@ -1076,15 +1081,9 @@ class Evaluator {
|
|
|
1076
1081
|
const prevEnv = this.environment;
|
|
1077
1082
|
this.environment = someEnv;
|
|
1078
1083
|
try {
|
|
1079
|
-
this.
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
if (this.isTruthy(returnValue.value)) {
|
|
1083
|
-
this.environment = prevEnv;
|
|
1084
|
-
return true;
|
|
1085
|
-
}
|
|
1086
|
-
} else {
|
|
1087
|
-
throw returnValue;
|
|
1084
|
+
const result = this.executeFunctionBody(someCallback);
|
|
1085
|
+
if (this.isTruthy(result)) {
|
|
1086
|
+
return true;
|
|
1088
1087
|
}
|
|
1089
1088
|
} finally {
|
|
1090
1089
|
this.environment = prevEnv;
|
|
@@ -1112,15 +1111,9 @@ class Evaluator {
|
|
|
1112
1111
|
const prevEnv = this.environment;
|
|
1113
1112
|
this.environment = everyEnv;
|
|
1114
1113
|
try {
|
|
1115
|
-
this.
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
if (!this.isTruthy(returnValue.value)) {
|
|
1119
|
-
this.environment = prevEnv;
|
|
1120
|
-
return false;
|
|
1121
|
-
}
|
|
1122
|
-
} else {
|
|
1123
|
-
throw returnValue;
|
|
1114
|
+
const result = this.executeFunctionBody(everyCallback);
|
|
1115
|
+
if (!this.isTruthy(result)) {
|
|
1116
|
+
return false;
|
|
1124
1117
|
}
|
|
1125
1118
|
} finally {
|
|
1126
1119
|
this.environment = prevEnv;
|
package/dist/parser.js
CHANGED
|
@@ -853,6 +853,11 @@ class Parser {
|
|
|
853
853
|
|
|
854
854
|
if (this.match("IDENTIFIER")) {
|
|
855
855
|
const identifier = this.previous();
|
|
856
|
+
// Check for single-param arrow function: x => ...
|
|
857
|
+
if (this.check("ARROW")) {
|
|
858
|
+
this.advance(); // Consume the ARROW
|
|
859
|
+
return this.arrowFunctionBody([identifier.lexeme]);
|
|
860
|
+
}
|
|
856
861
|
if (this.check("LEFT_PAREN")) {
|
|
857
862
|
this.advance(); // Consume the LEFT_PAREN
|
|
858
863
|
return this.finishCall(identifier);
|
|
@@ -876,6 +881,10 @@ class Parser {
|
|
|
876
881
|
}
|
|
877
882
|
|
|
878
883
|
if (this.match("LEFT_PAREN")) {
|
|
884
|
+
// Check if this could be arrow function params
|
|
885
|
+
if (this.isArrowFunctionParams()) {
|
|
886
|
+
return this.arrowFunctionWithParams();
|
|
887
|
+
}
|
|
879
888
|
const expr = this.expression();
|
|
880
889
|
this.consume("RIGHT_PAREN", "Expected ) after expression");
|
|
881
890
|
return expr;
|
|
@@ -1042,6 +1051,109 @@ class Parser {
|
|
|
1042
1051
|
};
|
|
1043
1052
|
}
|
|
1044
1053
|
|
|
1054
|
+
/**
|
|
1055
|
+
* Checks if current position looks like arrow function parameters
|
|
1056
|
+
* Looks ahead to find matching ) and checks for =>
|
|
1057
|
+
* @returns {boolean} True if this looks like arrow function params
|
|
1058
|
+
*/
|
|
1059
|
+
isArrowFunctionParams() {
|
|
1060
|
+
// Save current position
|
|
1061
|
+
const startPos = this.current;
|
|
1062
|
+
|
|
1063
|
+
// Empty params: () =>
|
|
1064
|
+
if (this.check("RIGHT_PAREN")) {
|
|
1065
|
+
// Check if next is =>
|
|
1066
|
+
if (
|
|
1067
|
+
this.tokens[this.current + 1] &&
|
|
1068
|
+
this.tokens[this.current + 1].type === "ARROW"
|
|
1069
|
+
) {
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// Try to match params pattern: identifier (comma identifier)*
|
|
1076
|
+
let parenDepth = 1;
|
|
1077
|
+
let pos = this.current;
|
|
1078
|
+
|
|
1079
|
+
while (pos < this.tokens.length && parenDepth > 0) {
|
|
1080
|
+
const token = this.tokens[pos];
|
|
1081
|
+
if (token.type === "LEFT_PAREN") {
|
|
1082
|
+
parenDepth++;
|
|
1083
|
+
} else if (token.type === "RIGHT_PAREN") {
|
|
1084
|
+
parenDepth--;
|
|
1085
|
+
}
|
|
1086
|
+
pos++;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// pos is now after the matching )
|
|
1090
|
+
// Check if next token is =>
|
|
1091
|
+
if (pos < this.tokens.length && this.tokens[pos].type === "ARROW") {
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Parses arrow function with parenthesized parameters
|
|
1100
|
+
* Called after LEFT_PAREN has been consumed
|
|
1101
|
+
* @returns {Object} Arrow function expression
|
|
1102
|
+
*/
|
|
1103
|
+
arrowFunctionWithParams() {
|
|
1104
|
+
const parameters = [];
|
|
1105
|
+
|
|
1106
|
+
// Parse parameters
|
|
1107
|
+
if (!this.check("RIGHT_PAREN")) {
|
|
1108
|
+
do {
|
|
1109
|
+
if (parameters.length >= 255) {
|
|
1110
|
+
throw new Error("No se pueden tener más de 255 parámetros");
|
|
1111
|
+
}
|
|
1112
|
+
const param = this.consume(
|
|
1113
|
+
"IDENTIFIER",
|
|
1114
|
+
"Se esperaba un nombre de parámetro",
|
|
1115
|
+
);
|
|
1116
|
+
parameters.push(param.lexeme);
|
|
1117
|
+
} while (this.match("COMMA"));
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
this.consume("RIGHT_PAREN", "Se esperaba ) después de los parámetros");
|
|
1121
|
+
this.consume("ARROW", "Se esperaba => después de los parámetros");
|
|
1122
|
+
|
|
1123
|
+
return this.arrowFunctionBody(parameters);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Parses arrow function body (expression or block)
|
|
1128
|
+
* @param {Array} parameters - Function parameters
|
|
1129
|
+
* @returns {Object} Arrow function expression
|
|
1130
|
+
*/
|
|
1131
|
+
arrowFunctionBody(parameters) {
|
|
1132
|
+
// Check if body is a block
|
|
1133
|
+
if (this.match("LEFT_BRACE")) {
|
|
1134
|
+
const body = this.block();
|
|
1135
|
+
this.consume(
|
|
1136
|
+
"RIGHT_BRACE",
|
|
1137
|
+
"Se esperaba } después del cuerpo de la función",
|
|
1138
|
+
);
|
|
1139
|
+
return {
|
|
1140
|
+
type: "ArrowFunction",
|
|
1141
|
+
parameters,
|
|
1142
|
+
body,
|
|
1143
|
+
isExpression: false,
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Body is a single expression (implicit return)
|
|
1148
|
+
const expression = this.expression();
|
|
1149
|
+
return {
|
|
1150
|
+
type: "ArrowFunction",
|
|
1151
|
+
parameters,
|
|
1152
|
+
body: expression,
|
|
1153
|
+
isExpression: true,
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1045
1157
|
/**
|
|
1046
1158
|
* Finishes parsing an array access
|
|
1047
1159
|
* @param {Object} array - The array being accessed
|
package/dist/tokenizer.js
CHANGED
package/package.json
CHANGED