diff --git a/lib/__test__/example_descriptor.ts b/lib/__test__/example_descriptor.ts index 239df48..aaff7a4 100644 --- a/lib/__test__/example_descriptor.ts +++ b/lib/__test__/example_descriptor.ts @@ -254,6 +254,8 @@ export class Food extends DataClass { return Food._all; } + public _price: float; + @GenieKey @GenieProperty("Name of the food item") public name: string; @@ -273,11 +275,20 @@ export class Food extends DataClass { }) { super({}); this.name = name; - this.price = price; + this._price = price; this.restaurant = restaurant; Food._all.push(this); } + async update() { + await new Promise((resolve) => { + setTimeout(() => { + resolve(void 0); + }, 10); + }); + this.price = this._price; + } + description(): {} { return { name: this.name, diff --git a/lib/dsl-descriptor.ts b/lib/dsl-descriptor.ts index 9e5eb8e..52ca04b 100644 --- a/lib/dsl-descriptor.ts +++ b/lib/dsl-descriptor.ts @@ -12,6 +12,13 @@ export class GenieObject { } } + /** + * This function is called after the object is created, and called before function calls and property access. + */ + update(): void | Promise { + return + } + // placeholder, should be replaced by GenieClass decorator static _createObject( this: T, diff --git a/lib/dsl/__test__/dsl-interpreter.test.ts b/lib/dsl/__test__/dsl-interpreter.test.ts index 944b489..749ed6c 100644 --- a/lib/dsl/__test__/dsl-interpreter.test.ts +++ b/lib/dsl/__test__/dsl-interpreter.test.ts @@ -145,6 +145,18 @@ test("find burger name", async () => { }); }); +test("find burger price", async () => { + const interpreter = new DslInterpreter(allDescriptors); + const funcCallResult = await interpreter.interpret( + "Restaurant.current().menu.matching(field: .name, value: \"hamburger\")[0].price" + ); + expect(funcCallResult).toEqual({ + objectType: "float", + type: "object", + value: 5 + }); +}); + test("best restaurant", async () => { const interpreter = new DslInterpreter(allDescriptors); const funcCallResult = await interpreter.interpret( @@ -195,7 +207,10 @@ test("add hamburger to the order (steps)", async () => { const funcCallResult: any[] = await interpreter.interpretSteps( "Restaurant.all().equals(field: .priceGrade, value: 1)[0].name" ); - expect((await interpreter.describeSteps(funcCallResult)).reverse()[1]).toEqual({ + const describeSteps =(await interpreter.describeSteps( + funcCallResult[funcCallResult.length - 1].steps + )).reverse() + expect((describeSteps[1])).toEqual({ type: "object", value: { address: "123 Main St, Palo Alto, USA", diff --git a/lib/dsl/dsl-interpreter.ts b/lib/dsl/dsl-interpreter.ts index 6232079..1726bd8 100644 --- a/lib/dsl/dsl-interpreter.ts +++ b/lib/dsl/dsl-interpreter.ts @@ -341,18 +341,19 @@ export class DslInterpreter { return lastResult; } - public async interpretSteps(input: string): Promise { + public async interpretSteps(input: string): Promise<{ ast: any, result: any, steps: {ast: any, result: any}[] }[]> { const ast = parse(input) as object[]; var lastResult = null; + let allSteps = []; for (const statement of ast) { // console.log(JSON.stringify(ast)); this.resolveSteps = []; this.resolveStepsEnabled = true; lastResult = await this.resolve(statement); this.resolveStepsEnabled = false; - return this.resolveSteps; + allSteps.push({ ast: statement, result: lastResult, steps: this.resolveSteps }); } - return lastResult; + return allSteps; } /** @@ -383,6 +384,7 @@ export class DslInterpreter { value: ast.value, }; } else { + await ast.value.update() return { type: "object", value: await ast.value.description() }; } } else { @@ -395,7 +397,7 @@ export class DslInterpreter { public async describeSteps(list: any[]) { const steps = [] for (const e of list) { - steps.push(await this.describe(e)) + steps.push(await this.describe(e.result)) } return steps; } @@ -528,6 +530,7 @@ export class DslInterpreter { } } else { if (isObject) { + await this.strip(parent).update(); fieldValue = this.strip(parent)[ast.access]; } else { fieldValue = classDescriptor.classConstructor[ast.access]; @@ -617,7 +620,7 @@ export class DslInterpreter { const parameter_entries = []; if (ast.parameters !== null) { for (const p of ast.parameters) { - parameter_entries.push([p.parameter, await this.resolve(p.value, env)]); + parameter_entries.push([p.parameter, await this.resolve(p.value, null)]); } } const parameters = new Map(parameter_entries); @@ -766,6 +769,9 @@ export class DslInterpreter { }], }; } else { + if (env.type === "object") { + await targetImplementation.update(); + } return { type: "array", value: (await targetImplementation[ast.func_name](matchedParameters)).map( @@ -787,6 +793,9 @@ export class DslInterpreter { objectType: returnType.original_type, }; } else { + if (env.type === "object") { + await targetImplementation.update(); + } return { type: "object", value: await(targetImplementation[ast.func_name](matchedParameters)), diff --git a/package-lock.json b/package-lock.json index 182af9d..a8f4e1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "reactgenie-dsl", - "version": "0.0.44", + "version": "0.0.45", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "reactgenie-dsl", - "version": "0.0.44", + "version": "0.0.45", "license": "Apache-2.0", "dependencies": { "@babel/cli": "^7.23.0", diff --git a/package.json b/package.json index f792b77..b271465 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reactgenie-dsl", - "version": "0.0.44", + "version": "0.0.45", "description": "A natural language parser based on a large language model", "scripts": { "prepare": "peggy lib/dsl/parser.pegjs -o lib/dsl/parser.gen.js && tsc",