Last active
December 16, 2024 17:49
-
-
Save kenwebb/64973dc6f7188262c3072570d48f2ea5 to your computer and use it in GitHub Desktop.
JavaScript - Abstract Syntax Tree (AST) 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Mon Dec 16 2024 12:49:09 GMT-0500 (Eastern Standard Time)--> | |
<XholonWorkbook> | |
<Notes><![CDATA[ | |
Xholon | |
------ | |
Title: JavaScript - Abstract Syntax Tree (AST) 2 | |
Description: | |
Url: http://www.primordion.com/Xholon/gwt/ | |
InternalName: 64973dc6f7188262c3072570d48f2ea5 based on 59bf08805972a394fe1e6311bb29f68a | |
Keywords: | |
My Notes | |
-------- | |
10 Dec 2024 | |
http://127.0.0.1:8080/Xholon.html?app=JavaScript+-+Abstract+Syntax+Tree+(AST)&src=lstr&gui=clsc&jslib=acorn | |
Note: the URL must have "&jslib=acorn" at the end | |
Learn how to parse JavaScript code using an AST tool such as a parser. | |
I want to use this capability in my "Industrial Dynamics - Chapter 15 - Xholonish - SubtreeGenerator" workbook. | |
16 Dec 2024 | |
This is version 2; same model but lots of details changed. | |
Instead of using me.UOR, this workbook uses just UOR. | |
### acorn | |
see ~/nodespace/acorn/READMEksw.txt for details on what I did to install and use acorn | |
it works in Dev Tools | |
### References | |
(1) search: JavaScript Abstract Syntax Tree | |
(2) https://astexplorer.net/ | |
Type JavaScript into left editor, and see the AST in the right pane. | |
The following code worked: | |
UOR.K=UOR.J+(DT)*(RRR.JK-SSR.JK) // L | |
IAR.K=IAR.J+(DT)*(SRR.JK-SSR.JK) // L | |
SSR.KL=UOR.K/DUR // R | |
RSR.K=RSR.J+(DT)*(1/DRR)*(RRR.JK-RSR.J) // L | |
IDR.K=(AIR)*(RSR.K) // A | |
ISR.K=IDR.K-IAR.K // A | |
PDR.KL=(ISR.K/DIR)+RSR.K // R | |
UOD.K=UOD.J+(DT)*(PDR.JK-SRR.JK) // L | |
SRR.KL=UOD.K/DUD // R | |
INSTP.K=STEP(20,1) // timing | |
RRR.KL=100.0+INSTP.K // R | |
- each line is an Expression Statement with its subtree | |
- it uses Parser: acorn-8.7.0 | |
(3) https://www.digitalocean.com/community/tutorials/js-traversing-ast | |
Read JavaScript Source Code, Using an AST | |
Published on February 9, 2019 | |
small example | |
Open Source ECMAScript parsers | |
they use the acorn parser | |
I should be able to use this page to help me get started. | |
(4) https://dev.to/marvinjude/abstract-syntax-trees-and-practical-applications-in-javascript-4a3 | |
Abstract Syntax Trees and Practical Applications in JavaScript | |
Jude Agboola | |
Posted on Oct 21, 2023 | |
- it uses astexplorer as a learning tool | |
- he uses the swc parser, rather than acorn | |
- the examples he works through are not that relevant to my needs | |
(5) https://swc.rs/ | |
SWC | |
Rust-based platform for the Web | |
SWC is an extensible Rust-based platform for the next generation of fast developer tools. | |
It's used by tools like Next.js, Parcel, and Deno, as well as companies like Vercel, ByteDance, Tencent, Shopify, Trip.com, and more. | |
SWC can be used for both compilation and bundling. | |
For compilation, it takes JavaScript / TypeScript files using modern JavaScript features and outputs valid code that is supported by all major browsers. | |
) https://swc.rs/docs/usage/core#parse | |
(6) https://github.com/acornjs/acorn | |
A small, fast, JavaScript-based JavaScript parser | |
) https://github.com/acornjs/acorn/tree/master/acorn-walk/ | |
]]></Notes> | |
<_-.XholonClass> | |
<PhysicalSystem/> | |
<AstParser/> | |
<!-- System Dynamics node types: Level Rate Auxiliary Constant --> | |
<SdNode superClass="Script"> | |
<SdLevel/> | |
<SdRate/> | |
<SdAux/> | |
<SdConst/> | |
</SdNode> | |
</_-.XholonClass> | |
<xholonClassDetails> | |
<Avatar><Color>black</Color></Avatar> | |
<PhysicalSystem><Color>white</Color></PhysicalSystem> | |
<SdLevel><Color>yellowgreen</Color></SdLevel> | |
<SdRate><Color>orangered</Color></SdRate> | |
<SdAux><Color>purple</Color></SdAux> | |
<SdConst><Color>gold</Color></SdConst> | |
<SdLevel><DefaultContent><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
me.println(me.name()); | |
//me.J = Number(me.J); | |
//me.K = Number(me.K); | |
//TESTING += me.role(); | |
//JKL.J += 11; | |
//console.log(JKL); | |
}, | |
act: function() { | |
// do the DYNAMO function | |
me.println(me.role() + "." + me.prop + ": " + me.K); | |
switch (me.role()) { | |
case "UOR": | |
// UOR.K=UOR.J+(DT)*(RRR.JK-SSR.JK) // L | |
UOR.K=UOR.J+(DT.vall)*(RRR.JK-SSR.JK); | |
break; | |
case "IAR": | |
// IAR.K=IAR.J+(DT)*(SRR.JK-SSR.JK) // L | |
IAR.K=IAR.J+(DT.vall)*(SRR.JK-SSR.JK); | |
break; | |
case "RSR": | |
// RSR.K=RSR.J+(DT)*(1/DRR)*(RRR.JK-RSR.J) // L | |
RSR.K=RSR.J+(DT.vall)*(1/DRR.vall)*(RRR.JK-RSR.J) | |
break; | |
case "UOD": | |
// UOD.K=UOD.J+(DT)*(PDR.JK-SRR.JK) // L | |
UOD.K=UOD.J+(DT.vall)*(PDR.JK-SRR.JK) | |
break; | |
default: break; | |
} | |
me.println("UOR .J .K " + UOR.J + " " + UOR.K); // YES | |
}, | |
preAct: function() { | |
//me.J = me.K; | |
switch (me.role()) { | |
case "UOR": UOR.J = UOR.K; break; | |
case "IAR": IAR.J = IAR.K; break; | |
case "RSR": RSR.J = RSR.K; break; | |
case "UOD": UOD.J = UOD.K; break; | |
default: break; | |
} | |
} | |
} | |
//# sourceURL=SdLevel.js | |
]]></DefaultContent></SdLevel> | |
<SdRate><DefaultContent><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
me.println(me.name()); | |
//me.JK = Number(me.JK); | |
//me.KL = Number(me.KL); | |
}, | |
act: function() { | |
// do the DYNAMO function | |
me.println(me.role() + "." + me.prop + ": " + me.KL); | |
switch (me.role()) { | |
case "SSR": | |
// SSR.KL=UOR.K/DUR // R | |
SSR.KL=UOR.K/DUR.vall | |
break; | |
case "PDR": | |
// PDR.KL=(ISR.K/DIR)+RSR.K // R | |
PDR.KL=(ISR.K/DIR.vall)+RSR.K | |
break; | |
case "SRR": | |
// SRR.KL=UOD.K/DUD // R | |
SRR.KL=UOD.K/DUD.vall | |
break; | |
default: break; | |
} | |
}, | |
preAct: function() { | |
//me.JK = me.KL; | |
switch (me.role()) { | |
case "SSR": SSR.JK = SSR.KL; break; | |
case "PDR": PDR.JK = PDR.KL; break; | |
case "SRR": SRR.JK = SRR.KL; break; | |
default: break; | |
} | |
} | |
} | |
//# sourceURL=SdRate.js | |
]]></DefaultContent></SdRate> | |
<SdAux><DefaultContent><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
me.println(me.name()); | |
//me.J = Number(me.J); | |
//me.K = Number(me.K); | |
}, | |
act: function() { | |
// do the DYNAMO function | |
me.println(me.role() + "." + me.prop + ": " + me.K); | |
switch (me.role()) { | |
case "IDR": | |
// IDR.K=(AIR)*(RSR.K) // A | |
IDR.K=AIR.vall*RSR.K | |
break; | |
case "ISR": | |
// ISR.K=IDR.K-IAR.K // A | |
ISR.K=IDR.K-IAR.K | |
break; | |
case "INSTP": | |
// INSTP.K=STEP(20,1) // timing | |
INSTP.K = 1 | |
break; | |
default: break; | |
} | |
}, | |
preAct: function() { | |
//me.J = me.K; | |
} | |
} | |
//# sourceURL=SdAux.js | |
]]></DefaultContent></SdAux> | |
<SdConst><DefaultContent><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
me.println(me.name()); | |
//me.J = Number(me.J); | |
//me.K = Number(me.K); | |
} | |
/*act: function() { | |
// do the DYNAMO function | |
me.println(me.role() + "." + me.prop + ": " + me.K); | |
switch (me.role()) { | |
case "IDR": | |
// IDR.K=(AIR)*(RSR.K) // A | |
IDR.K=AIR.vall*RSR.K | |
break; | |
case "ISR": | |
// ISR.K=IDR.K-IAR.K // A | |
ISR.K=IDR.K-IAR.K | |
break; | |
case "INSTP": | |
// INSTP.K=STEP(20,1) // timing | |
INSTP.K = 1 | |
break; | |
default: break; | |
} | |
},*/ | |
/*preAct: function() { | |
me.J = me.K; | |
}*/ | |
} | |
//# sourceURL=SdConstbehavior.js | |
]]></DefaultContent></SdConst> | |
</xholonClassDetails> | |
<PhysicalSystem> | |
<!-- DYNAMO constants | |
AIR=3.0 | |
DIR=2.0 | |
DRR=2.0 | |
DT =0.5 | |
DUD=2.0 | |
DUR=1.0 | |
--> | |
<!--<SdConst roleName="AIR" vall="3.0"/> | |
<SdConst roleName="DIR" vall="2.0"/> | |
<SdConst roleName="DRR" vall="2.0"/> | |
<SdConst roleName="DT" vall="0.5"/> | |
<SdConst roleName="DUD" vall="2.0"/> | |
<SdConst roleName="DUR" vall="1.0"/>--> | |
<AstParser> | |
<Attribute_String> | |
AIR.vall=1.5 // constant | |
DIR.vall=1.5 // constant | |
DRR.vall=1.5 // constant | |
DT.vall=1.5 // constant | |
DUD.vall=1.5 // constant | |
DUR.vall=1.5 // constant | |
UOR.K=UOR.J+(DT)*(RRR.JK-SSR.JK) // L | |
IAR.K=IAR.J+(DT)*(SRR.JK-SSR.JK) // L | |
SSR.KL=UOR.K/DUR // R | |
RSR.K=RSR.J+(DT)*(1/DRR)*(RRR.JK-RSR.J) // L | |
IDR.K=(AIR)*(RSR.K) // A | |
ISR.K=IDR.K-IAR.K // A | |
PDR.KL=(ISR.K/DIR)+RSR.K // R | |
UOD.K=UOD.J+(DT)*(PDR.JK-SRR.JK) // L | |
SRR.KL=UOD.K/DUD // R | |
INSTP.K=STEP(20,1) // timing | |
RRR.KL=100.0+INSTP.K // R | |
</Attribute_String> | |
</AstParser> | |
</PhysicalSystem> | |
<AstParserbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
// 16 Dec 2024 Note: I had written 6 lines of code before the above line; it contained less-than and greater-than symbols; failed to load all the behavior nodes | |
// and, after fixing that line, all 6 lines were lost when I loaded the workbook | |
// LESSON - DO NOT include any text before the opening XML tag | |
//TESTING = "AstParser"; // this is available in all my Xholon behavior nodes | |
//NODES = this; | |
//JKL = {J:101, K:102}; // yes - JKL is available in all my Xholon behavior nodes | |
// I need to manually (for now) add the following: | |
// levels | |
UOR = {J:0, K:0}; | |
IAR = {J:0, K:0}; | |
RSR = {J:0, K:0}; | |
UOD = {J:0, K:0}; | |
// rates | |
SSR = {JK:0, KL:0}; | |
PDR = {JK:0, KL:0}; | |
SRR = {JK:0, KL:0}; | |
// aux | |
IDR = {J:0, K:0}; | |
ISR = {J:0, K:0}; | |
INSTP = {J:0, K:0}; | |
// constants | |
AIR = {vall: 3.0}; | |
DIR = {vall: 3.0}; | |
DRR = {vall: 3.0}; | |
DT = {vall: 3.0}; | |
DUD = {vall: 3.0}; | |
DUR = {vall: 3.0}; | |
var me, code, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
me.println(me.name()); | |
code = me.first().text(); | |
me.println(code); | |
//console.log(JKL); // NODES, ABC, $wnd.ABC, DEF, GHI | |
const ast = $wnd.acorn.Parser.parse(code, {ecmaVersion: 2020}); | |
const leftobjnamearr = []; | |
const leftpropnamearr = []; | |
const allportsarr = []; // an array where each item is itself an array | |
console.log(ast); | |
const body = ast.body; // an array | |
for (var i = 0; i < body.length; i++) { | |
const item = body[i]; | |
const portsarr = []; | |
const extype = item.expression.type; | |
const exoperator = item.expression.operator; | |
const exleft = item.expression.left; | |
const exright = item.expression.right; | |
const leftobjname = item.expression.left.object.name; | |
const leftpropname = item.expression.left.property.name; | |
const rightoperator = item.expression.right.operator; | |
// add object names to portsarr | |
this.collectPorts(exright, portsarr); | |
leftobjnamearr.push(leftobjname); | |
leftpropnamearr.push(leftpropname); | |
me.println("type:" + extype + " operator:" + exoperator + " obj.prop:" + leftobjname + "." + leftpropname + " rightop:" + rightoperator); | |
allportsarr.push(portsarr); | |
} | |
me.println(leftobjnamearr.join(",")); | |
const nodetype = (nodename, prop, myportsarr) => { | |
//const myportsarr = myportsstr.split(","); | |
let ntype = "SdNode"; | |
switch (prop) { | |
case "K": ntype = myportsarr[0] == nodename ? "SdLevel" : "SdAux"; break; | |
case "KL": ntype = "SdRate"; break; | |
default: ntype = "SdConst"; break; | |
} | |
return ntype; | |
} | |
// <Script>initializerscriptstr</Script/> | |
// $wnd.xh.root().append("<Script>UOR2 = {J:1, K:2}; IAR2 = {J:3.0, K:4.0}; SSR2 = {KL:5.0}; IDR2 = {K:6.0}; console.log(UOR2, IAR2, SSR2, IDR2)</Script>"); // TEST this works! | |
// TODO use J K or JK KL depending on leftpropnamearr[index] | |
const initializerscriptstr = | |
leftobjnamearr.map((item, index) => item + "={" + (leftpropnamearr[index] == "K" ? "J" : "JK") + ":11," + leftpropnamearr[index] + ":12" + "}", "").join("\n"); | |
console.log(initializerscriptstr); | |
const xstr = "<Script>" + initializerscriptstr + "</Script>"; | |
console.log(xstr); | |
$wnd.xh.root().append(xstr); | |
const nodes = "<_-.nodes>\n" | |
+ leftobjnamearr.map((item, index) => '<' + nodetype(item, leftpropnamearr[index], allportsarr[index]) + ' roleName="' + item | |
+ '" prop="' + leftpropnamearr[index] | |
+ '" ports="' + allportsarr[index] | |
+ '"/>', "").join("\n") | |
+ "\n</_-.nodes>"; | |
me.println(nodes); | |
me.parent().append(nodes); | |
let newnode = me.next(); | |
while (newnode) { | |
let portsarr = newnode.ports.split(","); | |
me.println(portsarr.length); | |
//if (portsarr[0]) { | |
for (var i = 0; i < portsarr.length; i++) { | |
const xpathexpr = "../SdNode[@roleName='" + portsarr[i] + "']"; | |
me.println(xpathexpr); | |
const remoteNode = newnode.xpath(xpathexpr); | |
newnode[portsarr[i]] = remoteNode; | |
} | |
newnode[newnode.prop] = 0; // J K JK KL | |
switch (newnode.prop) { | |
case "K": newnode["J"] = 0; break; | |
case "KL": newnode["JK"] = 0; break; | |
default: break; | |
} | |
newnode = newnode.next(); | |
} | |
//$wnd.xh.root().append("<Script>UOR2 = {J:1, K:2}; IAR2 = {J:3.0, K:4.0}; SSR2 = {KL:5.0}; IDR2 = {K:6.0}; console.log(UOR2, IAR2, SSR2, IDR2)</Script>"); // TEST this works! | |
}, | |
act: function() { | |
//me.println(me.name()); | |
//me.println(TESTING); | |
}, | |
// anode an AST node item.expression.right | |
// ports arr | |
collectPorts: function(node, parr) { | |
if (node.type == "Identifier") { | |
parr.push(node.name); | |
} | |
else if (node.object?.type == "Identifier") { | |
parr.push(node.object.name); | |
} | |
if (node.left) { | |
this.collectPorts(node.left, parr); | |
} | |
if (node.right) { | |
this.collectPorts(node.right, parr) | |
} | |
} | |
} | |
//# sourceURL=AstParserbehavior.js | |
]]></AstParserbehavior> | |
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg"> | |
<g> | |
<title>AstParser</title> | |
<rect id="PhysicalSystem/AstParser" fill="#98FB98" height="50" width="50" x="25" y="0"/> | |
<g> | |
<title>UOR</title> | |
<rect id="PhysicalSystem/XhNode[@roleName='UOR']" fill="#6AB06A" height="50" width="10" x="80" y="0"/> | |
</g> | |
</g> | |
</svg> | |
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
</XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment