dal-ast-js 0.0.1-dev

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.
@@ -0,0 +1,31 @@
1
+ import sys
2
+ import json
3
+ import argparse
4
+ from Synthesizer import Synthesizer
5
+
6
+ def main(argv):
7
+
8
+ args_parser = argparse.ArgumentParser(
9
+ description="Synthesizes a python program given the AST"
10
+ )
11
+
12
+ args_parser.add_argument(
13
+ "--ast",
14
+ required=True,
15
+ help="Path to ast file"
16
+ )
17
+
18
+ parsed_args = args_parser.parse_args(argv[1:])
19
+
20
+ try:
21
+ with open(parsed_args.ast, 'r') as f:
22
+ tree = json.loads(f.read())
23
+ except Exception as e:
24
+ print(f"Invalid arguments: {str(e)}", file=sys.stderr)
25
+ return -1
26
+
27
+ synth = Synthesizer(tree)
28
+ synth.run()
29
+
30
+ if __name__ == "__main__":
31
+ sys.exit(main(sys.argv))
@@ -0,0 +1,8 @@
1
+ {
2
+ "set": {
3
+ "description": "set(<target>,<keys>,<value>)"
4
+ },
5
+ "create": {
6
+ "description": "create(<name>,<type>,<role>)"
7
+ }
8
+ }
@@ -0,0 +1,362 @@
1
+ import ast
2
+ from helper import getVariableNameWithKeys
3
+
4
+ def getSynthesizedNode(node):
5
+ '''
6
+ Get the AST node given the dalAST metadata.
7
+
8
+ DAL Identifiers: get<Identifier>Ast
9
+ Commands: getCmd<CommandName>Ast
10
+ '''
11
+ type = node["type"]
12
+ if (type == "cmd"):
13
+ cmd = node["command"]
14
+ funcName = f"getCmd{cmd[0].upper() +cmd[1:]}Ast"
15
+ else:
16
+ funcName = f"get{type[0].upper() +type[1:]}Ast"
17
+
18
+ if (funcName in globals()):
19
+ return globals()[funcName](node)
20
+
21
+ def getCmdLogAst(node):
22
+ '''
23
+ log(<behavior>, <name>, <type>, <value>)
24
+
25
+ semanticLogger.logParticipant(<behavior>, <name>, <type>, <value>)
26
+
27
+ '''
28
+ behavior = node["args"][0]["value"]
29
+ name = node["args"][1]["value"]
30
+ type = node["args"][2]["value"]
31
+ value = node["args"][3]["value"]
32
+ return ast.Expr(
33
+ value=ast.Call(
34
+ func=ast.Attribute(
35
+ value=ast.Name(id="semanticLogger", ctx=ast.Load()),
36
+ attr="logParticipant",
37
+ ctx=ast.Load(),
38
+ ),
39
+ args=[
40
+ ast.Constant(value=behavior),
41
+ ast.Constant(value=name),
42
+ ast.Constant(value=type),
43
+ ast.Name(id=value, ctx=ast.Load()),
44
+ ],
45
+ keywords=[],
46
+ )
47
+ )
48
+
49
+ def getBehaviorAst(node):
50
+ '''
51
+ def <behaviorName>():
52
+ global worldState
53
+ '''
54
+ return ast.FunctionDef(
55
+ name=node["behaviorName"],
56
+ args=ast.arguments(
57
+ posonlyargs=[],
58
+ args=[],
59
+ kwonlyargs=[],
60
+ kw_defaults=[],
61
+ defaults=[],
62
+ vararg=None,
63
+ kwarg=None
64
+ ),
65
+ body=[
66
+ ast.Global(
67
+ names=["worldState"]
68
+ )
69
+ ],
70
+ decorator_list=[]
71
+ )
72
+
73
+ def getDesignAst(node):
74
+ '''
75
+ design = <design_Name>
76
+ '''
77
+ return ast.Assign(
78
+ targets=[
79
+ ast.Name(id="design", ctx=ast.Store())
80
+ ],
81
+ value=ast.Constant(value=node["design_name"][0]["value"])
82
+ )
83
+
84
+ def getWhileAst(node):
85
+ '''
86
+ while <condition>:
87
+ <body>
88
+ '''
89
+ return ast.While(
90
+ test=ast.Name(id=node["args"][0]["value"], ctx=ast.Load()),
91
+ body=[],
92
+ orelse=[]
93
+ )
94
+
95
+ def getIfAst(node):
96
+ '''
97
+ if <condition>:
98
+ <body>
99
+ '''
100
+ condition = node["args"][0]["value"]
101
+ return ast.If(
102
+ test=ast.Name(id=condition, ctx=ast.Load()),
103
+ body=[],
104
+ orelse=[],
105
+ )
106
+
107
+ def getCmdGetInputAst(node):
108
+ '''
109
+ This is a registered synthesis. I am claiming
110
+ that input() realises the meaning of the behavior
111
+ defined by getInput()
112
+
113
+ <output> = input()
114
+ '''
115
+ name = node["args"][0]["value"]
116
+ prompt = node["args"][1]["value"]
117
+ return ast.Assign(
118
+ targets=[
119
+ ast.Name(id=name, ctx=ast.Store())
120
+ ],
121
+ value=ast.Call(
122
+ func=ast.Name(id="input", ctx=ast.Load()),
123
+ args=[ast.Constant(value=prompt)],
124
+ keywords=[]
125
+ )
126
+ )
127
+
128
+ def getCmdSetAst(node):
129
+ '''
130
+ <name>[<keys>] = <value>
131
+ '''
132
+ name = node["args"][0]["value"]
133
+ keys = node["args"][1]["value"]
134
+ rawValue = node["args"][2]["value"]
135
+
136
+ if (node["args"][2]["type"] == "name"):
137
+ value = ast.Name(id=rawValue, ctx=ast.Load())
138
+ else:
139
+ value = ast.Constant(value=rawValue)
140
+
141
+ return ast.Assign(
142
+ targets=[
143
+ getVariableNameWithKeys(name, keys)
144
+ ],
145
+ value=value,
146
+ )
147
+
148
+ def getCmdInsertAst(node):
149
+ '''
150
+ Command: insert(<target>, <keys>, <value>, <index>)
151
+
152
+ Synthesized: <target>[<keys>].insert(<index>, <value>)
153
+ '''
154
+ target = node["args"][0]["value"]
155
+ keys = node["args"][1]["value"]
156
+ value = node["args"][2]["value"]
157
+ index = node["args"][3]["value"]
158
+ return ast.Expr(
159
+ value=ast.Call(
160
+ func=ast.Attribute(
161
+ value= getVariableNameWithKeys(target, keys),
162
+ attr="insert",
163
+ ctx=ast.Load()
164
+ ),
165
+ args=[
166
+ ast.Constant(index),
167
+ ast.Name(id=value, ctx=ast.Load()),
168
+ ],
169
+ keywords=[]
170
+ )
171
+ )
172
+
173
+ def getCmdGetAst(node):
174
+ '''
175
+ Command: get(<target>, <source>, <keys>)
176
+
177
+ Synthesized: <target> = <source>[<keys>]
178
+ '''
179
+ target = node["args"][0]["value"]
180
+ source = node["args"][1]["value"]
181
+ keys = node["args"][2]["value"]
182
+ return ast.Assign(
183
+ value=getVariableNameWithKeys(source, keys),
184
+ targets=[ast.Name(id=target, ctx=ast.Store())]
185
+ )
186
+
187
+ def getCmdSelectAst(node):
188
+ '''
189
+ Command: select(<nextBehavior>)
190
+
191
+ Synthesized: return <nextBehavior>
192
+ '''
193
+ returnValue = node["args"][0]["value"]
194
+ return ast.Return(
195
+ value=ast.Constant(value=returnValue)
196
+ )
197
+
198
+ def getCmdDisplayAst(node):
199
+ '''
200
+ Command: display(<prompt>)
201
+
202
+ Synthesized: print(<prompt>)
203
+ '''
204
+ display = node["args"][0]["value"]
205
+
206
+ return ast.Expr(
207
+ value=ast.Call(
208
+ func=ast.Name(id="print", ctx=ast.Load()),
209
+ args=[
210
+ ast.parse(display, mode="eval").body
211
+ ],
212
+ keywords=[]
213
+ )
214
+ )
215
+
216
+ def getCmdIsEqualAst(node):
217
+ '''
218
+ Command: isEqual(choice, "a", isAdd)
219
+
220
+ Synthesized: isAdd = choice == "a"
221
+ '''
222
+ output = node["args"][2]["value"]
223
+
224
+ if (node["args"][0]["type"] == "name"):
225
+ cmp1 = ast.Name(id=node["args"][0]["value"], ctx=ast.Load())
226
+ else:
227
+ cmp1 = ast.Constant(value=node["args"][0]["value"])
228
+
229
+ if (node["args"][1]["type"] == "name"):
230
+ cmp2 = ast.Name(id=node["args"][1]["value"], ctx=ast.Load())
231
+ else:
232
+ cmp2 = ast.Constant(value=node["args"][1]["value"])
233
+
234
+ return ast.Assign(
235
+ targets=[
236
+ ast.Name(id=output, ctx=ast.Store())
237
+ ],
238
+ value=ast.Compare(
239
+ left=cmp1,
240
+ ops=[ast.Eq()],
241
+ comparators=[cmp2],
242
+ ),
243
+ )
244
+
245
+ def getCmdGetFromPosAst(node):
246
+ '''
247
+ Command: getFromPos(book, basket, 0)
248
+
249
+ Synthesized:
250
+ book = basket[0]
251
+ '''
252
+ target = node["args"][0]["value"]
253
+ source = node["args"][1]["value"]
254
+ index = node["args"][2]["value"]
255
+
256
+ return ast.Assign(
257
+ targets=[
258
+ ast.Name(id=target, ctx=ast.Store())
259
+ ],
260
+ value=ast.Subscript(
261
+ value=ast.Name(id=source, ctx=ast.Load()),
262
+ slice=ast.Constant(value=index),
263
+ ctx=ast.Load()
264
+ )
265
+ )
266
+
267
+ def getCmdRemoveFromPosAst(node):
268
+ '''
269
+ Command: removeFromPos(book, basket, 0)
270
+
271
+ Synthesized:
272
+ book = basket(0)
273
+ '''
274
+ target = node["args"][0]["value"]
275
+ source = node["args"][1]["value"]
276
+ index = node["args"][2]["value"]
277
+
278
+ return ast.Assign(
279
+ targets=[
280
+ ast.Name(id=target, ctx=ast.Store())
281
+ ],
282
+ value=ast.Call(
283
+ func=ast.Attribute(
284
+ value=ast.Name(id=source, ctx=ast.Load()),
285
+ attr="pop",
286
+ ctx=ast.Load()
287
+ ),
288
+ args=[ast.Constant(value=index)],
289
+ keywords=[]
290
+ )
291
+ )
292
+
293
+
294
+ def getCmdRunAst(node):
295
+ '''
296
+ Command: run(<startBehavior>)
297
+
298
+ Synthesized:
299
+
300
+ if __name__ == "__main__":
301
+ nextBehavior = <startBehavior>
302
+ while nextBehavior:
303
+ nextBehavior = globals()[nextBehavior]()
304
+ '''
305
+ nextBehavior = node["args"][0]["value"]
306
+ return ast.If(
307
+ test=ast.Compare(
308
+ left=ast.Name(id="__name__", ctx=ast.Load()),
309
+ ops=[ast.Eq()],
310
+ comparators=[
311
+ ast.Constant(value="__main__")
312
+ ],
313
+ ),
314
+ body=[
315
+ ast.Assign(
316
+ targets=[
317
+ ast.Name(id="nextBehavior", ctx=ast.Store())
318
+ ],
319
+ value=ast.Constant(value=nextBehavior),
320
+ ),
321
+ ast.Assign(
322
+ targets=[
323
+ ast.Name(id="worldState", ctx=ast.Store())
324
+ ],
325
+ value=ast.Dict(
326
+ keys=[],
327
+ values=[]
328
+ )
329
+ ),
330
+ ast.While(
331
+ test=ast.Name(id="nextBehavior", ctx=ast.Load()),
332
+ body=[
333
+ ast.Assign(
334
+ targets=[
335
+ ast.Name(id="nextBehavior", ctx=ast.Store())
336
+ ],
337
+ value=ast.Call(
338
+ func=ast.Subscript(
339
+ value=ast.Call(
340
+ func=ast.Name(
341
+ id="globals",
342
+ ctx=ast.Load(),
343
+ ),
344
+ args=[],
345
+ keywords=[],
346
+ ),
347
+ slice=ast.Name(
348
+ id="nextBehavior",
349
+ ctx=ast.Load(),
350
+ ),
351
+ ctx=ast.Load(),
352
+ ),
353
+ args=[],
354
+ keywords=[],
355
+ ),
356
+ )
357
+ ],
358
+ orelse=[],
359
+ ),
360
+ ],
361
+ orelse=[],
362
+ )
@@ -0,0 +1,13 @@
1
+ import ast
2
+
3
+ def getVariableNameWithKeys(name, keys):
4
+ current = ast.Name(id=name, ctx=ast.Load())
5
+
6
+ for key in keys:
7
+ current = ast.Subscript(
8
+ value=current,
9
+ slice=ast.Constant(value=key),
10
+ ctx=ast.Store()
11
+ )
12
+
13
+ return current
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from pathlib import Path
3
+ from clp_logging.handlers import ClpKeyValuePairStreamHandler
4
+
5
+ import os, uuid
6
+
7
+ ADLI_EXECUTION_ID = str(uuid.uuid4())
8
+
9
+ path = Path(os.path.dirname(__file__)) / f"{ADLI_EXECUTION_ID}.clp.zst"
10
+ clp_handler = ClpKeyValuePairStreamHandler(open(path, "wb"))
11
+ logger = logging.getLogger("semanticLogger")
12
+ logger.setLevel(logging.INFO)
13
+ logger.addHandler(clp_handler)
14
+
15
+ class LoggingHelper:
16
+ '''
17
+ This class holds all the logging functions used by the
18
+ instrumented code during runtime.
19
+ '''
20
+ def logParticipant(self, behaviorId, participantName, participantType, participantValue):
21
+ entry = {}
22
+ entry["type"] = "participant"
23
+ entry["behaviorName"] = behaviorId
24
+ entry["participantName"] = participantName
25
+ entry["participantType"] = participantType
26
+ entry["participantValue"] = participantValue
27
+ logger.info(entry)
28
+
29
+ def logArgument(self, behaviorId, argumentName, argumentValue):
30
+ entry = {}
31
+ entry["type"] = "argument"
32
+ entry["behaviorName"] = behaviorId
33
+ entry["argumentName"] = argumentName
34
+ entry["argumentValue"] = argumentValue
35
+ logger.info(entry)
36
+
37
+ def logInput(self, behaviorId, inputName, inputValue):
38
+ entry = {}
39
+ entry["type"] = "behavior"
40
+ entry["behaviorName"] = behaviorId
41
+ entry["inputName"] = inputName
42
+ entry["inputValue"] = inputValue
43
+ logger.info(entry)
44
+
45
+ def logBehavior(self, behaviorId):
46
+ entry = {}
47
+ entry["type"] = "behavior"
48
+ entry["behaviorName"] = behaviorId
49
+ logger.info(entry)
50
+
51
+ def logFailure(self, behaviorId):
52
+ entry = {}
53
+ entry["type"] = "failure"
54
+ entry["behaviorName"] = behaviorId
55
+ logger.info(entry)
56
+
57
+ semanticLogger = LoggingHelper()
@@ -0,0 +1,76 @@
1
+ from LoggingHelper import semanticLogger
2
+ design = 'library_manager'
3
+
4
+ def createBasket():
5
+ global worldState
6
+ basket = []
7
+ worldState['basket'] = basket
8
+ return 'getChoice'
9
+
10
+ def getChoice():
11
+ global worldState
12
+ choice = input('\nGet user choice (a for add book, g for get book, else exit): ')
13
+ semanticLogger.logParticipant('getChoice', 'choice', 'string', choice)
14
+ isAdd = choice == 'a'
15
+ isGet = choice == 'g'
16
+ worldState['choice'] = choice
17
+ if isAdd:
18
+ return 'getName'
19
+ if isGet:
20
+ return 'getBookFromBasket'
21
+
22
+ def getBookFromBasket():
23
+ global worldState
24
+ basket = worldState['basket']
25
+ book = basket.pop(0)
26
+ worldState['book'] = book
27
+ return 'getFirstLetterOfBookName'
28
+
29
+ def getFirstLetterOfBookName():
30
+ global worldState
31
+ book = worldState['book']
32
+ name = book['name']
33
+ firstLetter = name[0]
34
+ print(f'Got book named {name} and it has first letter {firstLetter}')
35
+ worldState['firstLetter'] = firstLetter
36
+ return 'getChoice'
37
+
38
+ def displayChoice():
39
+ global worldState
40
+ choice = worldState['choice']
41
+ print(f'User Choice: {choice}')
42
+ return 'getChoice'
43
+
44
+ def getName():
45
+ global worldState
46
+ name = input('\nPlease enter book name: ')
47
+ semanticLogger.logParticipant('getName', 'name', 'string', name)
48
+ worldState['name'] = name
49
+ return 'createBook'
50
+
51
+ def createBook():
52
+ global worldState
53
+ name = worldState['name']
54
+ book = {}
55
+ book['name'] = name
56
+ worldState['book'] = book
57
+ return 'addBookToBasket'
58
+
59
+ def addBookToBasket():
60
+ global worldState
61
+ book = worldState['book']
62
+ basket = worldState['basket']
63
+ basket.insert(0, book)
64
+ worldState['basket'] = basket
65
+ return 'showBasket'
66
+
67
+ def showBasket():
68
+ global worldState
69
+ basket = worldState['basket']
70
+ print(f'Basket Contents: {basket}')
71
+ return 'getChoice'
72
+ if __name__ == '__main__':
73
+ nextBehavior = 'createBasket'
74
+ worldState = {}
75
+ while nextBehavior:
76
+ nextBehavior = globals()[nextBehavior]()
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from pathlib import Path
3
+ from clp_logging.handlers import ClpKeyValuePairStreamHandler
4
+
5
+ import os, uuid
6
+
7
+ ADLI_EXECUTION_ID = str(uuid.uuid4())
8
+
9
+ path = Path(os.path.dirname(__file__)) / f"{ADLI_EXECUTION_ID}.clp.zst"
10
+ clp_handler = ClpKeyValuePairStreamHandler(open(path, "wb"))
11
+ logger = logging.getLogger("semanticLogger")
12
+ logger.setLevel(logging.INFO)
13
+ logger.addHandler(clp_handler)
14
+
15
+ class LoggingHelper:
16
+ '''
17
+ This class holds all the logging functions used by the
18
+ instrumented code during runtime.
19
+ '''
20
+ def logParticipant(self, behaviorId, participantName, participantType, participantValue):
21
+ entry = {}
22
+ entry["type"] = "participant"
23
+ entry["behaviorName"] = behaviorId
24
+ entry["participantName"] = participantName
25
+ entry["participantType"] = participantType
26
+ entry["participantValue"] = participantValue
27
+ logger.info(entry)
28
+
29
+ def logArgument(self, behaviorId, argumentName, argumentValue):
30
+ entry = {}
31
+ entry["type"] = "argument"
32
+ entry["behaviorName"] = behaviorId
33
+ entry["argumentName"] = argumentName
34
+ entry["argumentValue"] = argumentValue
35
+ logger.info(entry)
36
+
37
+ def logInput(self, behaviorId, inputName, inputValue):
38
+ entry = {}
39
+ entry["type"] = "behavior"
40
+ entry["behaviorName"] = behaviorId
41
+ entry["inputName"] = inputName
42
+ entry["inputValue"] = inputValue
43
+ logger.info(entry)
44
+
45
+ def logBehavior(self, behaviorId):
46
+ entry = {}
47
+ entry["type"] = "behavior"
48
+ entry["behaviorName"] = behaviorId
49
+ logger.info(entry)
50
+
51
+ def logFailure(self, behaviorId):
52
+ entry = {}
53
+ entry["type"] = "failure"
54
+ entry["behaviorName"] = behaviorId
55
+ logger.info(entry)
56
+
57
+ semanticLogger = LoggingHelper()
@@ -0,0 +1,3 @@
1
+ Contains helpers used by the synthesized output.
2
+
3
+ - LoggingHelper: Creates CLP logging instance and makes it available to the synthesized program.
@@ -0,0 +1,9 @@
1
+ This contains a synthesizer (written in python) that will synthesize an implementation of a design specified in the Design Abstraction Language.
2
+
3
+ I am writing it in python because the AST library is very convenient and I will invoke it from the workbench using the nodejs runner.
4
+
5
+ # Example Usage
6
+ ```bash
7
+ python3 dal_ast_synthesizer.py --ast ./asts/lib_manager_ast.json
8
+ ```
9
+
@@ -0,0 +1,45 @@
1
+ import {describe, expect, it} from "vitest";
2
+ import {resolve} from "path"
3
+ import {readFile, unlink, writeFile} from "fs/promises"
4
+ import { DesignValidator } from "../src/DesignValidator";
5
+ import { DalParser } from "../src/Parser";
6
+ import { DalLexer} from "../src/Lexer";
7
+ import { DalAstGenerator } from "../src/DalAstGenerator";
8
+
9
+
10
+ describe("Lexer", () => {
11
+ it("basic source", async () => {
12
+ const filePath = resolve(__dirname, "./designs/library_manager.dal")
13
+ const source = await readFile(filePath)
14
+ const lexer = new DalLexer(source.toString());
15
+
16
+
17
+ const tokens_output_path = resolve(__dirname, "./output/test_tokens.json")
18
+ await writeFile(
19
+ tokens_output_path,
20
+ JSON.stringify(lexer.scannedTokens, null, 4)
21
+ );
22
+
23
+ const parser = new DalParser(lexer.scannedTokens);
24
+ const ast_output_path = resolve(__dirname, "./output/ast.json")
25
+ await writeFile(
26
+ ast_output_path,
27
+ JSON.stringify(parser.ast, null, 4)
28
+ );
29
+
30
+ const validator = new DesignValidator(parser.ast);
31
+ validator.run();
32
+ });
33
+
34
+ it("tests direct ast generation", async () => {
35
+ const filePath = resolve(__dirname, "./designs/library_manager.dal")
36
+ const source = await readFile(filePath)
37
+ const ast = new DalAstGenerator().run(source.toString());
38
+ const ast_output_path = resolve(__dirname, "./output/ast_direct_gen.json")
39
+ await writeFile(
40
+ ast_output_path,
41
+ JSON.stringify(ast, null, 4)
42
+ );
43
+ });
44
+
45
+ });