Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b48ad02
discover this is to hard coded
jitsedesmet Apr 2, 2025
e8d5047
update types and factory
jitsedesmet Apr 4, 2025
7201e6a
ponder generator architecture
jitsedesmet Apr 4, 2025
d06aef0
first go at rounttripping generation
jitsedesmet Apr 7, 2025
d0d988c
limit generator to work on Nodes
jitsedesmet Apr 7, 2025
2f99bcc
allow string generation skipping
jitsedesmet Apr 7, 2025
0e5347d
lets start with testing triple blocks and paths
jitsedesmet Apr 7, 2025
f63be3c
first test for objectListparser
jitsedesmet Apr 7, 2025
1f555b8
add range arithmetics
jitsedesmet Apr 7, 2025
a8307cf
reformat AST
jitsedesmet Apr 8, 2025
c57ac13
use enum approach to sourceLocation
jitsedesmet Jun 19, 2025
ed3c383
reinstate lost files
jitsedesmet Jun 20, 2025
9c71565
semi compiling parser
jitsedesmet Jun 23, 2025
47b27a8
reinstate parser test files
jitsedesmet Jun 30, 2025
62b55cb
tests responese look fine
jitsedesmet Jul 1, 2025
0bb1e80
sink results to file
jitsedesmet Jul 1, 2025
77c9160
introduction of localized type as a split between Node types and loc …
jitsedesmet Jul 2, 2025
21cd49c
part of quety generation
jitsedesmet Jul 2, 2025
0bb8f60
my generator no like me
jitsedesmet Jul 3, 2025
89f6859
initial startings on rounttripping completed
jitsedesmet Jul 4, 2025
61e3d6f
magic tarnsformer;
jitsedesmet Jul 7, 2025
0c41bc9
transform using subTypes
jitsedesmet Jul 9, 2025
10f705a
on the way to adding tests for auto generation
jitsedesmet Jul 9, 2025
ea74296
enable spec test and validators
jitsedesmet Jul 10, 2025
74212ee
reinstate ADJUST parser
jitsedesmet Jul 14, 2025
ed9b051
reinstate sparql 1.2 parser
jitsedesmet Jul 14, 2025
5055099
working sparql 1.2 parser
jitsedesmet Jul 15, 2025
5df2739
generation of SPARQL 1.2
jitsedesmet Jul 15, 2025
538eb35
factory uses mixins
jitsedesmet Jul 16, 2025
d675c05
fix lockfile
jitsedesmet Jul 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
50 changes: 50 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
### Round Tripping

We decided to implement round tripping by creating a `location` field for eachAST node.
The location indicates a source string and a start and end index of the string representation of that AST node within the source string.
To reduce string repetitions, an undefined source string means this node shares the same source string as its parent.

We considered round tripping where spaces and special cases were captured as part of a round tripping type (RTT) field in each AST,
but that solution was not maintainable. The issue was that some strings are not materialized in teh AST such as an empty group: `{ { } . } }.`
Tracking this as part of the AST creates a complex 'ownership' problem.
Additionally capturing the complexity of all edge-cases proved to be difficult on a grammar basis, as such, reasoning over code became a nightmare.
Lastly, capturing round tripping info in your AST types creates for a strongly types AST, but that comes with a maintainability tradeoff.
Looking back, there were many issues with the approach.
The reason it was attempted in the first place was so IDE-like tooling could be implemented easily since the RTT types could be edited themselves,
instead of editing the string representations.

### Altered AST from SPARQL.JS

This library will replace [SPARQL.JS](https://github.com/RubenVerborgh/SPARQL.js/) in the Comunica project, as such there was a debate on whether the AST should be the same since it would require minimal refactoring.
In the end we decided to change the AST to be closer to typical ASTs so language tolling could easily be integrated ontop of the generator output.
Converting the AST to algebra was previously done by [SPARQL algebra.js](https://github.com/joachimvh/SPARQLAlgebra.js),
which will be merged as a package in this monorepo.
It will be up to the algebra generator to optimize the AST to a structure most suitable by query engines such as Comunica.

### Generation
Our generator must support
replacement operations like: https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-replacing-a-node
but also replacements with specific string formats. using `path.replaceWith(F.someType(..., { source: 'own string', start: 0, end: length-1; }))`

The generator is initialized with sources and skip-ranges.
A rule sharing source with parent will start with a catchup, only afterward will it start generating underlying rules.
The catchup function of the generator knows when a rule is replaced since it will be registered as a skip-range, and skip-ranges are not generated using catchup's.

Generation rules that have an ast that is not Localized SHOULD NOT print since they do noy auto catchup.

Currently, the constructed generator does not support that you have a source tracked node within something that is generated.
That means that you need to use `F.forcedAutoGenTree()` to force the whole subtree on some node to be auto generated too.
In the future we could change this implementation in such a way that we would detect when source bound nodes are present and use range arithmetics.
We do not do that yet to keep things simple.

### Altering subrule results

Be careful when recreating nodes that have been created by subrules since the recreation might lose information if the a modified grammar adds more fields to the node.
Example, do:
```
res[0].subject = subject;
res[0].loc = C.factory.sourceLocation(subject, res[0]);
// WARNING for future use: overwriting elements like this is
// bad practice since it will remove future extensions
// res[0] = C.factory.triple(subject, predicate, object, C.factory.sourceLocation(subject, object));
```
39 changes: 39 additions & 0 deletions engines/generator-sparql-1-1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# TRAQULA SPARQL 1.1 generator

TRAQULA Generator Sparql 1.1 is a [SPARQL 1.1](https://www.w3.org/TR/sparql11-query/#grammar) query generator for TypeScript.
It can generate SPARQL given the AST created by [TRAQULA parser SPARQL 1-1](https://github.com/comunica/traqula/tree/main/engines/parser-sparql-1-1).

## Installation

```bash
npm install @traqula/generator-sparql-1-1
```

or

```bash
yarn add @traqula/generator-sparql-1-1
```

## Import

Either through ESM import:

```javascript
import {Parser} from 'engines/generator-sparql-1-1';
```

_or_ CJS require:

```javascript
const Parser = require('engines/generator-sparql-1-1').Parser;
```

## Usage

This package contains a `Generator` that is able to generate SPARQL 1.1 queries:

```typescript
const generator = new Generator();
const abstractSyntaxTree = generator.generate(abstractSyntaxTree);
```
118 changes: 118 additions & 0 deletions engines/generator-sparql-1-1/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { GeneratorBuilder } from '@traqula/core';
import { gram, Factory } from '@traqula/rules-sparql-1-1';
import type * as T11 from '@traqula/rules-sparql-1-1';

const queryOrUpdate: T11.SparqlGeneratorRule<'queryOrUpdate', T11.Query | T11.Update> = {
name: 'queryOrUpdate',
gImpl: ({ SUBRULE }) => (ast, { factory: F }) => {
if (F.isQuery(ast)) {
SUBRULE(gram.query, ast, undefined);
} else {
SUBRULE(gram.update, ast, undefined);
}
},
};

export const sparql11GeneratorBuilder = GeneratorBuilder.createBuilder(<const> [
gram.query,
gram.selectQuery,
gram.constructQuery,
gram.describeQuery,
gram.askQuery,
gram.selectClause,
])
.addMany(
gram.update,
gram.update1,
gram.load,
gram.clear,
gram.drop,
gram.create,
gram.copy,
gram.move,
gram.add,
gram.insertData,
gram.deleteData,
gram.deleteWhere,
gram.modify,
gram.graphRef,
gram.graphRefAll,
gram.quads,
gram.quadsNotTriples,
)
.addRule(gram.aggregate)
.addMany(
gram.datasetClauseStar,
gram.usingClauseStar,
)
.addMany(
gram.argList,
gram.expression,
gram.iriOrFunction,
)
.addMany(
gram.prologue,
gram.prefixDecl,
gram.baseDecl,
gram.varOrTerm,
gram.var_,
gram.graphTerm,
)
.addMany(
gram.rdfLiteral,
gram.iri,
gram.iriFull,
gram.prefixedName,
gram.blankNode,
)
.addRule(gram.path)
.addMany(
gram.solutionModifier,
gram.groupClause,
gram.havingClause,
gram.orderClause,
gram.limitOffsetClauses,
)
.addMany(
gram.triplesBlock,
gram.collectionPath,
gram.blankNodePropertyListPath,
gram.triplesNodePath,
gram.graphNodePath,
)
.addMany(
gram.whereClause,
gram.generatePattern,
gram.groupGraphPattern,
gram.graphPatternNotTriples,
gram.optionalGraphPattern,
gram.graphGraphPattern,
gram.serviceGraphPattern,
gram.bind,
gram.inlineData,
gram.minusGraphPattern,
gram.groupOrUnionGraphPattern,
gram.filter,
)
.addRule(queryOrUpdate);

export class Generator {
private readonly generator = sparql11GeneratorBuilder.build();
private readonly factory = new Factory();

public generate(ast: T11.Query | T11.Update, origSource = ''): string {
return this.generator.queryOrUpdate(ast, {
factory: this.factory,
offset: 0,
origSource,
}, undefined);
}

public generatePath(ast: T11.Path, origSource = ''): string {
return this.generator.path(ast, {
factory: this.factory,
offset: 0,
origSource,
}, undefined);
}
}
49 changes: 49 additions & 0 deletions engines/generator-sparql-1-1/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@traqula/generator-sparql-1-1",
"type": "module",
"version": "0.0.0",
"description": "SPARQL 1.1 generator",
"lsd:module": true,
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/comunica/traqula.git",
"directory": "engines/generator-sparql-1-1"
},
"bugs": {
"url": "https://github.com/comunica/traqula/issues"
},
"sideEffects": false,
"exports": {
"import": "./lib/index.js",
"require": "./lib/index.cjs"
},
"main": "lib/index.js",
"publishConfig": {
"access": "public"
},
"files": [
"lib/**/*.cjs",
"lib/**/*.d.ts",
"lib/**/*.js",
"lib/**/*.js.map"
],
"engines": {
"node": ">=18.0"
},
"typings": "lib/index",
"scripts": {
"build": "yarn build:ts && yarn build:transpile",
"build:ts": "node \"../../node_modules/typescript/bin/tsc\"",
"build:transpile": " node \"../../node_modules/esbuild/bin/esbuild\" --format=cjs --bundle --log-level=error --outfile=lib/index.cjs lib/index.ts"
},
"dependencies": {
"@traqula/core": "^0.0.0",
"@traqula/rules-sparql-1-1": "^0.0.0"
},
"devDependencies": {
"@traqula/parser-sparql-1-1": "^0.0.0",
"@traqula/rules-sparql-1-1": "^0.0.0",
"@traqula/test-utils": "^0.0.0"
}
}
Loading
Loading