Content for jsdw.me. Please submit a PR if you'd like to correct spelling mistakes and such.
brew install zola
(last tried at 0.18.0).zola serve
for local devzola build
to build.
A small DSL/interpreter that can be used to evaluate simple expressions
License: MIT License
Content for jsdw.me. Please submit a PR if you'd like to correct spelling mistakes and such.
brew install zola
(last tried at 0.18.0).zola serve
for local devzola build
to build.I've defined a simple language with some operators and when testing a really awful nested if condition code, the execution time jumps from just 3ms (great) to over a second.
For example:
if(answer(8)=="test1" and numeric(7)<3, res0,
if(answer(8)=="test1" and numeric(7)==3, res1,
if(answer(8)=="test1" and numeric(7)==4, res1,
if(answer(8)=="test2" and numeric(7)==1, res0,
if(answer(8)=="test2" and numeric(7)==2, res1,
if(answer(8)=="test2" and numeric(7)==3, res2,
if(answer(8)=="test2" and numeric(7)==4, res2,
if(answer(8)=="test3" and numeric(7)==1, res1,
if(answer(8)=="test3" and numeric(7)==2, res2,
if(answer(8)=="test3" and numeric(7)==3, res3,
if(answer(8)=="test3" and numeric(7)==4, res3,
if(answer(8)=="test4" and numeric(7)==1, res1,
if(answer(8)=="test4" and numeric(7)==2, res3,
if(answer(8)=="test4" and numeric(7)>2, res4, res0))))))))))))))
The answer
and numeric
calls just lookup the number in a dict/map object defined in the scope.
And the operators are defined as follows:
With the following helper function:
const numberFunDefault = (a, b, def, fun) => {
let va = Number(a?.eval());
let vb = Number(b?.eval());
if (isNaN(va)) {
va = def;
}
if (isNaN(vb)) {
vb = def;
}
return fun(va, vb);
};
When debugging in chrome, looks like a lot of time is lost in GC:
Any ideas what could be improved? Note that these kind of nested ifs will actually not be written like this, but rather as a lookup table which runs really quick, but while testing this seemed like an issue.
@jsdw hey, are you still maintaining this? Further, does this use eval
or any other unsafe primitive that may fail CSP policies?
Thanks.
hey does it support array literal or object literal syntaxes?
is it possible to write one as a scope
function?
charlie
P.S. this library is awesome, been building with it for a while
Just wondering, what's the best way to return user-friendly errors? The errors are a bit cryptic and sometimes even deeply nested in recursive structures.
For example, this is not enough:
const getErrorLine = (expr, start, end) => {
let text = expr.slice(start, start + end + 8) || 'char 0';
return text;
};
const raiseError = (expr, res) => {
let err = res.value;
if (err.kind === 'EVAL_THROW') {
throw new Error(`The code evaluation threw an error`);
} else if (
err.kind === 'FUNCTION_NOT_DEFINED' ||
err.kind === 'NOT_A_FUNCTION'
) {
throw new Error(`Function not defined`);
} else if (err.pos?.start !== undefined && err.pos?.end !== undefined) {
let text = getErrorLine(expr, err.pos.start, err.pos.end);
throw new Error(
`The code has syntax errors or invalid variable names near: ${text}`
);
} else {
throw new Error(`The code has syntax errors.`);
}
};
Because for EVAL_THROW
, the error is sometimes nested like this:
Would it be possible to allow the use of any string as a custom operator?
A cool use case I'd like to explore would be to use this library to write a simple "query" language for some stuff
import angu from "angu";
import _ from "lodash";
const releases = [
{
id: 1,
tags: ["a", "b", "c"]
},
{
id: 2,
tags: ["a", "1"]
},
{
id: 3,
tags: ["b", "2"]
},
{
id: 4,
tags: ["c", "3"]
}
];
const ctx = {
scope: {
"&": (a, b) => _.unionWith([...a.eval(), ...b.eval()], x => x.id),
"|": (a, b) => _.uniqBy([...a.eval(), ...b.eval()], x => x.id),
"?": (a, b) => releases.filter(r => r[a.eval()].includes(b.eval()))
},
precedence: [["?"], ["&"], ["|"]]
};
const resultsA = angu.evaluate("'tags' ? 'a'", ctx);
console.log("A: ", JSON.stringify(resultsA.value));
const resultsBandC = angu.evaluate("'tags' ? 'b' & 'tags' ? 'c'", ctx);
console.log("B AND C's: ", JSON.stringify(resultsBandC.value));
const results1or3 = angu.evaluate("'tags' ? '1' | 'tags' ? '3'", ctx);
console.log("1 OR 3's: ", JSON.stringify(results1or3.value));
I'd love to be able to use
"INCLUDES" instead of "?"
"AND" instead of "&"
"OR" instead of "|"
I can run the strings through a 'variable' replacement step beforehand, but I think it'd be awesome if the library could support this out of the box.
A comment on reddit asked how one might create a simple example JSON query language. I think that this would be a great example to have.
Offhand, I suspect I would define the .
operator so that you can write things like foo.bar.0.lark
in the simplest case to define field/array acceses. I'd have to look at some of the abilities that something like jq
provides to see where to go from there!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.