simple-graph-query 1.0.1 → 1.1.1

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.
package/README.md CHANGED
@@ -1,73 +1,118 @@
1
- # simple-graph-query
1
+ # Forge Expression Evaluator
2
2
 
3
- **simple-graph-query** is a lightweight query engine for navigating and extracting tuples from finite graphs using a relational logic inspired by Alloy. It runs entirely client-side and supports a small, composable query language based on set comprehension and relational navigation.
3
+ A TypeScript library for evaluating Forge language expressions with a browser-compatible UMD bundle.
4
4
 
5
- ## What It Does
5
+ ## Installation
6
6
 
7
- This tool lets you run queries like:
7
+ ```bash
8
+ npm install forge-expr-evaluator
9
+ ```
10
+
11
+ ## Usage
8
12
 
13
+ ### Browser (UMD Bundle)
14
+ ```html
15
+ <script src="node_modules/forge-expr-evaluator/dist/forge-expr-evaluator.bundle.js"></script>
16
+ <script>
17
+ const evaluator = new ForgeExprEvaluator.ForgeExprEvaluatorUtil(datum, sourceCode);
18
+ const result = evaluator.evaluateExpression("some Board", 0);
19
+ console.log(result);
20
+ </script>
9
21
  ```
10
- { x, y : Person | y in x.friend* }
11
- { x, y : Person | x.friend = y }
12
- { x : Person | x in x.friend* }
22
+
23
+ ### Node.js
24
+ ```javascript
25
+ const { ForgeExprEvaluatorUtil } = require('forge-expr-evaluator');
26
+
27
+ const evaluator = new ForgeExprEvaluatorUtil(datum, sourceCode);
28
+ const result = evaluator.evaluateExpression("some Board", 0);
29
+ console.log(result);
13
30
  ```
14
31
 
15
- over JSON-encoded graphs like:
16
-
17
- ```json
18
- {
19
- "nodes": [
20
- { "id": "a", "type": "Person" },
21
- { "id": "b", "type": "Person" },
22
- { "id": "c", "type": "Person" }
23
- ],
24
- "edges": [
25
- { "from": "a", "to": "b", "label": "friend" },
26
- { "from": "b", "to": "c", "label": "friend" }
27
- ]
28
- }
32
+ ### TypeScript
33
+ ```typescript
34
+ import { ForgeExprEvaluatorUtil, DatumParsed } from 'forge-expr-evaluator';
35
+
36
+ const datum: DatumParsed = {
37
+ parsed: {
38
+ instances: [/* your data */],
39
+ bitwidth: 4
40
+ },
41
+ data: "<alloy>...</alloy>"
42
+ };
43
+
44
+ const sourceCode = `
45
+ sig Board { ... }
46
+ // your Forge signatures and predicates
47
+ `;
48
+
49
+ const evaluator = new ForgeExprEvaluatorUtil(datum, sourceCode);
50
+ const result = evaluator.evaluateExpression("some Board", 0);
29
51
  ```
30
52
 
31
- And returns results like:
53
+ ## API
54
+
55
+ ### `ForgeExprEvaluatorUtil`
56
+
57
+ #### Constructor
58
+ ```typescript
59
+ new ForgeExprEvaluatorUtil(datum: DatumParsed, sourceCode: string)
60
+ ```
32
61
 
33
- ```json
34
- [
35
- ["a", "b"],
36
- ["a", "c"],
37
- ["b", "c"]
38
- ]
62
+ #### Methods
63
+ ```typescript
64
+ evaluateExpression(expression: string, instanceIndex?: number): EvaluationResult
39
65
  ```
40
66
 
41
- ## What Logic Does It Support
67
+ ### Types
68
+ - `DatumParsed`: Data structure containing Forge model instances
69
+ - `EvaluationResult`: Result of expression evaluation (value or error)
70
+ - `EvalResult`: Successful evaluation result (string | number | boolean | Tuple[])
42
71
 
43
- `simple-graph-query` evaluates first-order relational queries over finite graph structures. Specifically:
72
+ ## Features
44
73
 
45
- - Typed variables: `{ x, y : Person | ... }`
46
- - Set comprehension: `{ tuple | condition }`
47
- - Relational navigation: `x.friend`, `x.friend.friend`
48
- - Equality: `x.friend = y`
49
- - Membership: `y in x.friend`
50
- - Transitive closure: `x.friend*`
74
+ - Browser-compatible UMD bundle (~688 KiB)
75
+ - TypeScript support with full type definitions
76
+ - Evaluates Forge expressions against model data
77
+ - No external dependencies in the bundle
78
+ - Works with Sterling/Alloy data formats
79
+
80
+ ## Development
81
+
82
+ ```bash
83
+ # Install dependencies
84
+ npm install
85
+
86
+ # Build the bundle
87
+ npm run build
88
+
89
+ # Run tests
90
+ npm test
91
+
92
+ # Serve demo locally
93
+ npm run serve
94
+ ```
51
95
 
52
- This is a subset of Alloy-style relational logic, evaluated over a fixed graph structure, with results returned as sets of tuples.
96
+ ## License
53
97
 
54
- ## Getting Started
98
+ MIT
55
99
 
56
- 1. Clone or unzip the repository.
57
- 2. Open `public/index.html` in your browser.
58
- 3. Paste a query like `{ x, y : Person | y in x.friend* }`.
59
- 4. Click Run and view the results.
100
+ ## Contributing
60
101
 
61
- ## Project Structure
102
+ 1. Fork the repository
103
+ 2. Create a feature branch
104
+ 3. Make your changes
105
+ 4. Add tests if needed
106
+ 5. Submit a pull request
62
107
 
63
- - `src/` – parser, evaluator, and AST
64
- - `examples/graph.json` – sample graph data
65
- - `public/index.html` – minimal UI to run queries
66
- - `runQuery(graph, query)` – main API
108
+ ## Credits
67
109
 
68
- ## TODO
110
+ _Note_: The evaluator makes use of a Forge parser built using ANTLR; this is largely taken from
111
+ the [parser developed by Siddhartha Prasad](https://github.com/sidprasad/forge-antlr/)
112
+ with some minor modifications to the grammar.
69
113
 
70
- - Support for `and`, `!=`, `no`, `some`
71
- - Regex-style navigation (`friend|coworker`)
72
- - Type checking and improved error handling
114
+ ## Related
73
115
 
116
+ - [Forge Language](https://forge.binghamton.edu/)
117
+ - [Alloy](https://alloytools.org/)
118
+ - [Sterling Visualizer](https://sterling-js.github.io/)
@@ -0,0 +1,58 @@
1
+ import { AbstractParseTreeVisitor } from "antlr4ts/tree/AbstractParseTreeVisitor";
2
+ import { ForgeVisitor } from "./forge-antlr/ForgeVisitor";
3
+ import { ExprContext, Expr1Context, Expr1_5Context, Expr2Context, Expr3Context, Expr4Context, Expr4_5Context, Expr5Context, Expr6Context, Expr7Context, Expr8Context, Expr9Context, Expr10Context, Expr11Context, Expr12Context, Expr13Context, Expr14Context, Expr15Context, Expr16Context, Expr17Context, Expr18Context, ExprListContext, NameContext, PredDeclContext, BlockContext, QualNameContext, QuantDeclListContext, NameListContext, QuantDeclContext } from "./forge-antlr/ForgeParser";
4
+ import { IDataInstance } from "./types";
5
+ export type SingleValue = string | number | boolean;
6
+ export type Tuple = SingleValue[];
7
+ export type EvalResult = SingleValue | Tuple[];
8
+ export declare function areTupleArraysEqual(a: Tuple[], b: Tuple[]): boolean;
9
+ export declare const SUPPORTED_BUILTINS: string[];
10
+ /**
11
+ * A recursive evaluator for Forge expressions.
12
+ * This visitor walks the parse tree and prints the type of operation encountered.
13
+ */
14
+ export declare class ForgeExprEvaluator extends AbstractParseTreeVisitor<EvalResult> implements ForgeVisitor<EvalResult> {
15
+ private environmentStack;
16
+ private freeVariableFinder;
17
+ private freeVariables;
18
+ private cachedResults;
19
+ private instanceData;
20
+ constructor(datum: IDataInstance);
21
+ private updateFreeVariables;
22
+ private constructFreeVariableKey;
23
+ private cacheResult;
24
+ private getIden;
25
+ protected aggregateResult(aggregate: EvalResult, nextResult: EvalResult): EvalResult;
26
+ protected defaultResult(): EvalResult;
27
+ visitPredDecl(ctx: PredDeclContext): EvalResult;
28
+ visitBlock(ctx: BlockContext): EvalResult;
29
+ visitExpr(ctx: ExprContext): EvalResult;
30
+ visitExpr1(ctx: Expr1Context): EvalResult;
31
+ visitExpr1_5(ctx: Expr1_5Context): EvalResult;
32
+ visitExpr2(ctx: Expr2Context): EvalResult;
33
+ visitExpr3(ctx: Expr3Context): EvalResult;
34
+ visitExpr4(ctx: Expr4Context): EvalResult;
35
+ visitExpr4_5(ctx: Expr4_5Context): EvalResult;
36
+ visitExpr5(ctx: Expr5Context): EvalResult;
37
+ visitExpr6(ctx: Expr6Context): EvalResult;
38
+ visitExpr7(ctx: Expr7Context): EvalResult;
39
+ visitExpr8(ctx: Expr8Context): EvalResult;
40
+ visitExpr9(ctx: Expr9Context): EvalResult;
41
+ visitExpr10(ctx: Expr10Context): EvalResult;
42
+ visitExpr11(ctx: Expr11Context): EvalResult;
43
+ visitExpr12(ctx: Expr12Context): EvalResult;
44
+ visitExpr13(ctx: Expr13Context): EvalResult;
45
+ visitExpr14(ctx: Expr14Context): EvalResult;
46
+ visitExpr15(ctx: Expr15Context): EvalResult;
47
+ visitExpr16(ctx: Expr16Context): EvalResult;
48
+ visitExpr17(ctx: Expr17Context): EvalResult;
49
+ getNameListValues(ctx: NameListContext): string[];
50
+ getQuantDeclValues(ctx: QuantDeclContext): Record<string, Tuple[]>;
51
+ getQuantDeclListValues(ctx: QuantDeclListContext): Record<string, Tuple[]>;
52
+ visitExpr18(ctx: Expr18Context): EvalResult;
53
+ visitExprList(ctx: ExprListContext): EvalResult;
54
+ visitName(ctx: NameContext): EvalResult;
55
+ visitQualName(ctx: QualNameContext): EvalResult;
56
+ private evaluateBinaryOperation;
57
+ private evaluateUnaryOperation;
58
+ }
@@ -0,0 +1,45 @@
1
+ import { AbstractParseTreeVisitor } from "antlr4ts/tree/AbstractParseTreeVisitor";
2
+ import { ParseTree } from "antlr4ts/tree/ParseTree";
3
+ import { ForgeVisitor } from "./forge-antlr/ForgeVisitor";
4
+ import { IDataInstance } from "./types";
5
+ import { BlockContext, Expr10Context, Expr11Context, Expr12Context, Expr13Context, Expr14Context, Expr15Context, Expr16Context, Expr17Context, Expr18Context, Expr1Context, Expr1_5Context, Expr2Context, Expr3Context, Expr4Context, Expr4_5Context, Expr5Context, Expr6Context, Expr7Context, Expr8Context, Expr9Context, ExprContext, ExprListContext, NameContext, NameListContext, PredDeclContext, QuantDeclContext, QuantDeclListContext } from "./forge-antlr/ForgeParser";
6
+ export type FreeVariables = Map<ParseTree, Set<string>>;
7
+ /**
8
+ * A recursive visitor to find all the free variables referenced in a forge
9
+ * expression.
10
+ */
11
+ export declare class ForgeExprFreeVariableFinder extends AbstractParseTreeVisitor<FreeVariables> implements ForgeVisitor<FreeVariables> {
12
+ private instanceData;
13
+ constructor(instanceData: IDataInstance);
14
+ protected aggregateResult(aggregate: FreeVariables, nextResult: FreeVariables): FreeVariables;
15
+ private addCtxToFreeVariableMap;
16
+ protected defaultResult(): FreeVariables;
17
+ visitPredDecl(ctx: PredDeclContext): FreeVariables;
18
+ visitBlock(ctx: BlockContext): FreeVariables;
19
+ getNameListValues(ctx: NameListContext): Set<string>;
20
+ getQuantDeclVarNames(ctx: QuantDeclContext): Set<string>;
21
+ getQuantDeclListVarNames(ctx: QuantDeclListContext): Set<string>;
22
+ visitExpr(ctx: ExprContext): FreeVariables;
23
+ visitExpr1(ctx: Expr1Context): FreeVariables;
24
+ visitExpr1_5(ctx: Expr1_5Context): FreeVariables;
25
+ visitExpr2(ctx: Expr2Context): FreeVariables;
26
+ visitExpr3(ctx: Expr3Context): FreeVariables;
27
+ visitExpr4(ctx: Expr4Context): FreeVariables;
28
+ visitExpr4_5(ctx: Expr4_5Context): FreeVariables;
29
+ visitExpr5(ctx: Expr5Context): FreeVariables;
30
+ visitExpr6(ctx: Expr6Context): FreeVariables;
31
+ visitExpr7(ctx: Expr7Context): FreeVariables;
32
+ visitExpr8(ctx: Expr8Context): FreeVariables;
33
+ visitExpr9(ctx: Expr9Context): FreeVariables;
34
+ visitExpr10(ctx: Expr10Context): FreeVariables;
35
+ visitExpr11(ctx: Expr11Context): FreeVariables;
36
+ visitExpr12(ctx: Expr12Context): FreeVariables;
37
+ visitExpr13(ctx: Expr13Context): FreeVariables;
38
+ visitExpr14(ctx: Expr14Context): FreeVariables;
39
+ visitExpr15(ctx: Expr15Context): FreeVariables;
40
+ visitExpr16(ctx: Expr16Context): FreeVariables;
41
+ visitExpr17(ctx: Expr17Context): FreeVariables;
42
+ visitExpr18(ctx: Expr18Context): FreeVariables;
43
+ visitExprList(ctx: ExprListContext): FreeVariables;
44
+ visitName(ctx: NameContext): FreeVariables;
45
+ }
@@ -0,0 +1,4 @@
1
+ import { ANTLRErrorListener, Recognizer, RecognitionException } from "antlr4ts";
2
+ export declare class ParseErrorListener implements ANTLRErrorListener<any> {
3
+ syntaxError(recognizer: Recognizer<any, any>, offendingSymbol: any, line: number, charPositionInLine: number, msg: string, e: RecognitionException | undefined): void;
4
+ }
@@ -0,0 +1,134 @@
1
+ import { ATN } from "antlr4ts/atn/ATN";
2
+ import { CharStream } from "antlr4ts/CharStream";
3
+ import { Lexer } from "antlr4ts/Lexer";
4
+ import { Vocabulary } from "antlr4ts/Vocabulary";
5
+ export declare class ForgeLexer extends Lexer {
6
+ static readonly OPEN_TOK = 1;
7
+ static readonly LEFT_SQUARE_TOK = 2;
8
+ static readonly RIGHT_SQUARE_TOK = 3;
9
+ static readonly AS_TOK = 4;
10
+ static readonly FILE_PATH_TOK = 5;
11
+ static readonly VAR_TOK = 6;
12
+ static readonly ABSTRACT_TOK = 7;
13
+ static readonly SIG_TOK = 8;
14
+ static readonly LEFT_CURLY_TOK = 9;
15
+ static readonly RIGHT_CURLY_TOK = 10;
16
+ static readonly EXTENDS_TOK = 11;
17
+ static readonly IN_TOK = 12;
18
+ static readonly PLUS_TOK = 13;
19
+ static readonly LONE_TOK = 14;
20
+ static readonly SOME_TOK = 15;
21
+ static readonly ONE_TOK = 16;
22
+ static readonly TWO_TOK = 17;
23
+ static readonly SET_TOK = 18;
24
+ static readonly FUNC_TOK = 19;
25
+ static readonly PFUNC_TOK = 20;
26
+ static readonly DISJ_TOK = 21;
27
+ static readonly COLON_TOK = 22;
28
+ static readonly WHEAT_TOK = 23;
29
+ static readonly PRED_TOK = 24;
30
+ static readonly DOT_TOK = 25;
31
+ static readonly FUN_TOK = 26;
32
+ static readonly LEFT_PAREN_TOK = 27;
33
+ static readonly RIGHT_PAREN_TOK = 28;
34
+ static readonly ASSERT_TOK = 29;
35
+ static readonly RUN_TOK = 30;
36
+ static readonly CHECK_TOK = 31;
37
+ static readonly FOR_TOK = 32;
38
+ static readonly BUT_TOK = 33;
39
+ static readonly EXACTLY_TOK = 34;
40
+ static readonly NONE_TOK = 35;
41
+ static readonly UNIV_TOK = 36;
42
+ static readonly IDEN_TOK = 37;
43
+ static readonly MINUS_TOK = 38;
44
+ static readonly IS_TOK = 39;
45
+ static readonly SAT_TOK = 40;
46
+ static readonly UNSAT_TOK = 41;
47
+ static readonly THEOREM_TOK = 42;
48
+ static readonly FORGE_ERROR_TOK = 43;
49
+ static readonly CHECKED_TOK = 44;
50
+ static readonly TEST_TOK = 45;
51
+ static readonly EXPECT_TOK = 46;
52
+ static readonly SUITE_TOK = 47;
53
+ static readonly BAR_TOK = 48;
54
+ static readonly ALL_TOK = 49;
55
+ static readonly SUFFICIENT_TOK = 50;
56
+ static readonly NECESSARY_TOK = 51;
57
+ static readonly CONSISTENT_TOK = 52;
58
+ static readonly INCONSISTENT_TOK = 53;
59
+ static readonly WITH_TOK = 54;
60
+ static readonly LET_TOK = 55;
61
+ static readonly BIND_TOK = 56;
62
+ static readonly OR_TOK = 57;
63
+ static readonly XOR_TOK = 58;
64
+ static readonly IFF_TOK = 59;
65
+ static readonly IMP_TOK = 60;
66
+ static readonly ELSE_TOK = 61;
67
+ static readonly AND_TOK = 62;
68
+ static readonly UNTIL_TOK = 63;
69
+ static readonly RELEASE_TOK = 64;
70
+ static readonly SINCE_TOK = 65;
71
+ static readonly TRIGGERED_TOK = 66;
72
+ static readonly NEG_TOK = 67;
73
+ static readonly ALWAYS_TOK = 68;
74
+ static readonly EVENTUALLY_TOK = 69;
75
+ static readonly AFTER_TOK = 70;
76
+ static readonly BEFORE_TOK = 71;
77
+ static readonly ONCE_TOK = 72;
78
+ static readonly HISTORICALLY_TOK = 73;
79
+ static readonly CARD_TOK = 74;
80
+ static readonly PPLUS_TOK = 75;
81
+ static readonly AMP_TOK = 76;
82
+ static readonly SUBT_TOK = 77;
83
+ static readonly SUPT_TOK = 78;
84
+ static readonly PRIME_TOK = 79;
85
+ static readonly TILDE_TOK = 80;
86
+ static readonly EXP_TOK = 81;
87
+ static readonly STAR_TOK = 82;
88
+ static readonly AT_TOK = 83;
89
+ static readonly BACKQUOTE_TOK = 84;
90
+ static readonly THIS_TOK = 85;
91
+ static readonly SEXPR_TOK = 86;
92
+ static readonly INST_TOK = 87;
93
+ static readonly EVAL_TOK = 88;
94
+ static readonly EXAMPLE_TOK = 89;
95
+ static readonly ARROW_TOK = 90;
96
+ static readonly EQ_TOK = 91;
97
+ static readonly LT_TOK = 92;
98
+ static readonly GT_TOK = 93;
99
+ static readonly LEQ_TOK = 94;
100
+ static readonly GEQ_TOK = 95;
101
+ static readonly NI_TOK = 96;
102
+ static readonly NO_TOK = 97;
103
+ static readonly SUM_TOK = 98;
104
+ static readonly INT_TOK = 99;
105
+ static readonly OPTION_TOK = 100;
106
+ static readonly COMMA_TOK = 101;
107
+ static readonly SLASH_TOK = 102;
108
+ static readonly NUM_CONST_TOK = 103;
109
+ static readonly IDENTIFIER_TOK = 104;
110
+ static readonly WS = 105;
111
+ static readonly CCOMMENT = 106;
112
+ static readonly COMMENT = 107;
113
+ static readonly MULTCOMMENT = 108;
114
+ static readonly LANG_DECL = 109;
115
+ static readonly channelNames: string[];
116
+ static readonly modeNames: string[];
117
+ static readonly ruleNames: string[];
118
+ private static readonly _LITERAL_NAMES;
119
+ private static readonly _SYMBOLIC_NAMES;
120
+ static readonly VOCABULARY: Vocabulary;
121
+ get vocabulary(): Vocabulary;
122
+ constructor(input: CharStream);
123
+ get grammarFileName(): string;
124
+ get ruleNames(): string[];
125
+ get serializedATN(): string;
126
+ get channelNames(): string[];
127
+ get modeNames(): string[];
128
+ private static readonly _serializedATNSegments;
129
+ private static readonly _serializedATNSegment0;
130
+ private static readonly _serializedATNSegment1;
131
+ static readonly _serializedATN: string;
132
+ static __ATN: ATN;
133
+ static get _ATN(): ATN;
134
+ }