Adding Regexps to Egg
Here we will add a function RegExp
to the Egg interpreter allowing the creation of Regular Expression objects.
Example
examples/regexp.egg
egg-oop-parser-solution git:(master) ✗ cat examples/regexp.egg
(
def(d, r/
(?<year> \d{4} ) -? # year
(?<month> \d{2} ) -? # month
(?<day> \d{2} ) # day
/x),
print(d.test("1987-07-14")), # true
def(m, d.exec("1987-07-14")),
print(util.inspect(m, {depth: null})), /* [ '1987-07-14', '1987', '07', '14', index: 0, input: '1987-07-14', groups: undefined ] */
print(m.index), # 0
def(x, RegExp.exec("2015-01-22", d)),
print(util.inspect(x, {depth: null})),
print(x.year), # 2015
print(x.month) # 02
)
The interpreter provided for this lab is not able to handle regular expressions. The following error is produced when trying to run the example above:
➜ egg-oop-parser-solution git:(master) ✗ bin/eggc.js examples/regexp.egg
➜ egg-oop-parser-solution git:(master) ✗ bin/evm examples/regexp.json
TypeError: Applying not a function or method TypeError: Applying not a function or method TypeError: Applying not a function or method ReferenceError: Undefined variable: util
at Apply.evaluate (/snapshot/2122-dist-egg/index.js:2:1230)
The error is about util
not being defined.
But if I use the interpreter provided in the repo ULL-ESIT-PL/private-egg (opens in a new tab) (private repo):
egg-oop-parser-solution git:(master) ✗ ls -l bin
total 24
-rwxr-xr-x 1 casianorodriguezleon staff 215 22 abr 13:10 egg
-rwxr-xr-x 1 casianorodriguezleon staff 1678 22 abr 12:29 eggc.js
lrwxr-xr-x 1 casianorodriguezleon staff 85 22 abr 12:32 evm -> /Users/casianorodriguezleon/campus-virtual/shared/egg/oop-evm-releases/evm-2122-macos
lrwxr-xr-x 1 casianorodriguezleon staff 78 23 abr 10:57 evm-crguezl.js -> /Users/casianorodriguezleon/campus-virtual/shared/egg/eloquentjsegg/bin/evm.js
-rwxr-xr-x 1 casianorodriguezleon staff 106 19 abr 2023 make-test
the example runs correctly:
➜ egg-oop-parser-solution git:(master) ✗ bin/evm-crguezl.js examples/regexp.json
true
[
'1987-07-14',
'1987',
'07',
'14',
index: 0,
input: '1987-07-14',
groups: undefined
]
0
[
'2015-01-22',
'2015',
'01',
'22',
index: 0,
input: '2015-01-22',
groups: undefined,
year: '2015',
month: '01',
day: '22'
]
2015
01
This means the release must be updated for next course 24/25.
tokens.js
src/token.js, branch:main egg-oop-parser-solution
...
const REGEXP = /(?<REGEXP>r\/((?:[^\/\\]|\\.)*)\/(\w*?\b)?)/;
REGEXP.value = (value) => {
let [source, flags] = value.split('/').slice(1);
return {
type: 'RegExp',
info: [ source, flags]
};
};
grammar.js
src/egg.ne, branch:main egg-oop-parser-solution
%STRING optProperties {% buildStringValue %}
| %NUMBER optProperties {% buildNumberValue %}
| %REGEXP optProperties {% buildRegexpValue %}
| bracketExp optProperties {% buildArray %}
| curlyExp optProperties {% buildObject %}
| "(" commaExp ")" {% buildDo %}
| %WORD applies {% buildWordApplies %}
buildRegexpValue
src/build-ast.js, branch:main egg-oop-parser-solution
function buildRegexpValue([regexpnode, properties]) {
if (!properties) {
regexpnode.type = "value";
return regexpnode;
}
return fromListToAST(regexpnode, properties);
}
j2a.js
lib/j2a.js, branch:main eloquentjs
const {j2a, json2AST, topEnv} = require("./registry.js");
const {Value, Word, Apply, Property} = require("./ast.js");
j2a['value'] = (j) => {
let obj = new Value(j);
// Lift the object if required
if (typeof obj.value === "object" && obj.value.type && topEnv[obj.value.type] && typeof topEnv[obj.value.type] === "function") {
debugger;
try {
obj.value = new topEnv[obj.value.type](...obj.value.info);
} catch (e) {
throw new TypeError(`Invalid attempt to create an ${obj.value.type}. Object value: ${obj.value}`);
}
}
return obj;
};
j2a['word'] = (j) => new Word(j);
j2a['apply'] = (j) => {... };
j2a['property'] = (j) => { ...};
module.exports = { j2a, json2AST };