diff --git a/.gitignore b/.gitignore index 85706df..96f4a02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /node_modules package-lock.json /dist -/src/*.js +/src/parser.js +/src/parser.terms.js /src/*.d.ts \ No newline at end of file diff --git a/LICENSE b/LICENSE index 23b98b7..b878ba1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2021 by Achraf Atauil and others +Copyright (C) 2021 by Achraf Atauil and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index 608db2d..f14a5a8 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,27 @@ { "name": "codemirror-lang-sparql", - "version": "0.1.1", + "version": "0.2.0", "description": "Sparql language support for CodeMirror", "scripts": { - "test": "mocha test/test.js", - "prepare": "rollup -c" + "build": "lezer-generator src/syntax.grammar -o src/parser && rollup -c", + "build-debug": "lezer-generator src/syntax.grammar --names -o src/parser && rollup -c", + "test": "mocha test/test.js" }, "type": "module", "main": "dist/index.cjs", "module": "dist/index.js", - "author": "Achraf Atauil", - "license": "MIT", "exports": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "types": "dist/index.d.ts", "sideEffects": false, + "author": "Achraf Atauil", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/aatauil/codemirror-lang-sparql.git" + }, "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/highlight": "^1.0.0", @@ -29,9 +34,6 @@ "rollup-plugin-dts": "^4.0.1", "rollup-plugin-ts": "^3.0.2", "typescript": "^4.3.4" - }, - "repository": { - "type" : "git", - "url" : "https://github.com/aatauil/codemirror-lang-sparql.git" } -} \ No newline at end of file + +} diff --git a/src/index.ts b/src/index.ts index d0d104d..454cfc0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,28 +1,23 @@ -import {parser} from "./syntax.grammar" -import {LRLanguage, LanguageSupport, indentNodeProp, foldNodeProp, foldInside, delimitedIndent} from "@codemirror/language" -import {styleTags, tags as t} from "@lezer/highlight" +import { parser } from "./syntax.grammar" +import { LRLanguage, LanguageSupport } from "@codemirror/language" +import { styleTags, tags as t } from "@lezer/highlight" export const SparqlLanguage = LRLanguage.define({ parser: parser.configure({ props: [ - indentNodeProp.add({ - Application: delimitedIndent({closing: ")", align: false}) - }), - foldNodeProp.add({ - Application: foldInside - }), styleTags({ - Identifier: t.variableName, - Boolean: t.bool, + Comment: t.comment, + "BASE PREFIX SELECT CONSTRUCT DESCRIBE WHERE DISTINCT REDUCED STR LANG LANGMATCHES DATATYPE ASK BOUND IRI URI BNODE RAND ABS CEIL FLOOR ROUND CONCAT STRLEN UCASE LCASE ENCODE_FOR_URI CONTAINS STRSTARTS STRENDS STRBEFORE STRAFTER YEAR MONTH DAY HOURS MINUTES SECONDS TIMEZONE TZ NOW UUID STRUUID MD5 SHA1 SHA256 SHA384 SHA512 COALESCE IF STRLANG STRDT SAMETERM ISIRI ISURI ISBLANK ISLITERAL ISNUMERIC COUNT SUM MIN MAX AVG SAMPLE GROUP_CONCAT SEPARATOR SUBSTR REPLACE REGEX EXISTS NOT IN GROUP BY HAVING ORDER ASC DESC LIMIT OFFSET VALUES UNDEF UNION OPTIONAL MINUS GRAPH SERVICE SILENT FILTER BIND AS FROM NAMED LOAD INTO TO CLEAR DROP CREATE ADD MOVE COPY INSERT DATA DELETE WITH DEFAULT ALL USING": t.keyword, + "Var ObjectListPath/..": t.variableName, String: t.string, - LineComment: t.lineComment, - "( )": t.paren + Integer: t.integer, + "Double Decimal": t.float, + "{ }": t.brace, + Langstag: t.annotation, + "TRUE FALSE": t.bool }) ] }), - languageData: { - commentTokens: {line: ";"} - } }) export function sparql() { diff --git a/src/syntax.grammar b/src/syntax.grammar index 4ef7bda..833e063 100644 --- a/src/syntax.grammar +++ b/src/syntax.grammar @@ -1,17 +1,11 @@ -@top QueryUnit { - Query -} - -@top UpdateUnit { - Update -} +@detectDelim -Prologue { - (BaseDecl | PrefixDecl)* +@top Unit { + ( Query | Update ) } Query { - Prologue ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery ) ValuesClause + Prologue ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery ) ValuesClause } Update { @@ -19,125 +13,67 @@ Update { } Update1 { - Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify -} - -DeleteClause { - 'DELETE' QuadPattern -} - -InsertClause { - 'INSERT' QuadPattern -} - -UsingClause { - 'USING' ( iri | 'NAMED' iri ) -} - -QuadData { - '{' Quads '}' -} - -QuadPattern { - '{' Quads '}' -} - -Quads { - TriplesTemplate? ( QuadsNotTriples '.'? TriplesTemplate? )* -} - -QuadsNotTriples { - 'GRAPH' VarOrIri '{' TriplesTemplate? '}' -} - - - -GraphOrDefault { - 'DEFAULT' | 'GRAPH'? iri -} - -GraphRefAll { - GraphRef | 'DEFAULT' | 'NAMED' | 'ALL' + ( Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify ) } Load { - 'LOAD' 'SILENT'? iri ( 'INTO' GraphRef )? + LOAD SILENT? Iri ( INTO GraphRef )? } Clear { - 'CLEAR' 'SILENT'? GraphRefAll + CLEAR SILENT? GraphRefAll } Drop { - 'DROP' 'SILENT'? GraphRefAll + DROP SILENT? GraphRefAll } Create { - 'CREATE' 'SILENT'? GraphRef + CREATE SILENT? GraphRef } Add { - 'ADD' 'SILENT'? GraphOrDefault 'TO' GraphOrDefault + ADD SILENT? GraphOrDefault TO GraphOrDefault } Move { - 'MOVE' 'SILENT'? GraphOrDefault 'TO' GraphOrDefault + MOVE SILENT? GraphOrDefault TO GraphOrDefault } Copy { - 'COPY' 'SILENT'? GraphOrDefault 'TO' GraphOrDefault + COPY SILENT? GraphOrDefault TO GraphOrDefault } InsertData { - 'INSERT DATA' QuadData + INSERT DATA QuadData } DeleteData { - 'DELETE DATA' QuadData + DELETE DATA QuadData } DeleteWhere { - 'DELETE WHERE' QuadPattern + DELETE WHERE QuadPattern } Modify { - ( 'WITH' iri )? ( DeleteClause InsertClause? | InsertClause ) UsingClause* 'WHERE' GroupGraphPattern + ( WITH Iri )? ( DeleteClause InsertClause? | InsertClause ) UsingClause* WHERE GroupGraphPattern } GraphRef { - 'GRAPH' iri -} - -AskQuery { - 'ASK' DatasetClause* WhereClause SolutionModifier -} - -DescribeQuery { - 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier -} - -ConstructQuery { - 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier ) -} - -TriplesTemplate { - TriplesSameSubject ( '.' TriplesTemplate? )? -} - -ConstructTemplate { - '{' ConstructTriples? '}' + GRAPH Iri } -ConstructTriples { - TriplesSameSubject ( '.' ConstructTriples? )? +Prologue { + (BaseDecl | PrefixDecl)* } -TriplesSameSubject { - VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList +BaseDecl { + BASE IriRef } -PropertyList { - PropertyListNotEmpty? +PrefixDecl { + PREFIX Namespace IriRef } SelectQuery { @@ -145,15 +81,7 @@ SelectQuery { } SelectClause { - 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '(' Expression 'AS' Var ')' ) )+ | '*' ) -} - -BaseDecl { - 'BASE' IriRef -} - -PrefixDecl { - 'PREFIX' Namespace IriRef + SELECT ( DISTINCT | REDUCED )? ( ( Var | ( '(' Expression AS Var ')' ) )+ | '*' ) } Expression { @@ -173,7 +101,16 @@ ValueLogical { } RelationalExpression { - NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )? + NumericExpression ( + '=' NumericExpression | + '!=' NumericExpression | + '<' NumericExpression | + '>' NumericExpression | + '<=' NumericExpression | + '>=' NumericExpression | + IN ExpressionList | + NOT IN ExpressionList + )? } NumericExpression { @@ -181,7 +118,15 @@ NumericExpression { } AdditiveExpression { - MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )* + MultiplicativeExpression ( + '+' MultiplicativeExpression | + '-' MultiplicativeExpression | + ( NumericLiteralPositive | NumericLiteralNegative ) + ( + ( '*' UnaryExpression ) | + ( '/' UnaryExpression ) + )* + )* } MultiplicativeExpression { @@ -196,7 +141,15 @@ UnaryExpression { } PrimaryExpression { - (BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var) + ( + BrackettedExpression | + BuiltInCall | + iriOrFunction | + RDFLiteral | + NumericLiteral | + BooleanLiteral | + Var + ) } BrackettedExpression { @@ -205,70 +158,70 @@ BrackettedExpression { BuiltInCall { ( Aggregate - | 'STR' '(' Expression ')' - | 'LANG' '(' Expression ')' - | 'LANGMATCHES' '(' Expression ',' Expression ')' - | 'DATATYPE' '(' Expression ')' - | 'BOUND' '(' Var ')' - | 'IRI' '(' Expression ')' - | 'URI' '(' Expression ')' - | 'BNODE' ( '(' Expression ')' | NIL ) - | 'RAND' NIL - | 'ABS' '(' Expression ')' - | 'CEIL' '(' Expression ')' - | 'FLOOR' '(' Expression ')' - | 'ROUND' '(' Expression ')' - | 'CONCAT' ExpressionList + | STR '(' Expression ')' + | LANG '(' Expression ')' + | LANGMATCHES '(' Expression ',' Expression ')' + | DATATYPE '(' Expression ')' + | BOUND '(' Var ')' + | IRI '(' Expression ')' + | URI '(' Expression ')' + | BNODE ( '(' Expression ')' | Nil ) + | RAND Nil + | ABS '(' Expression ')' + | CEIL '(' Expression ')' + | FLOOR '(' Expression ')' + | ROUND '(' Expression ')' + | CONCAT ExpressionList | SubstringExpression - | 'STRLEN' '(' Expression ')' + | STRLEN '(' Expression ')' | StrReplaceExpression - | 'UCASE' '(' Expression ')' - | 'LCASE' '(' Expression ')' - | 'ENCODE_FOR_URI' '(' Expression ')' - | 'CONTAINS' '(' Expression ',' Expression ')' - | 'STRSTARTS' '(' Expression ',' Expression ')' - | 'STRENDS' '(' Expression ',' Expression ')' - | 'STRBEFORE' '(' Expression ',' Expression ')' - | 'STRAFTER' '(' Expression ',' Expression ')' - | 'YEAR' '(' Expression ')' - | 'MONTH' '(' Expression ')' - | 'DAY' '(' Expression ')' - | 'HOURS' '(' Expression ')' - | 'MINUTES' '(' Expression ')' - | 'SECONDS' '(' Expression ')' - | 'TIMEZONE' '(' Expression ')' - | 'TZ' '(' Expression ')' - | 'NOW' NIL - | 'UUID' NIL - | 'STRUUID' NIL - | 'MD5' '(' Expression ')' - | 'SHA1' '(' Expression ')' - | 'SHA256' '(' Expression ')' - | 'SHA384' '(' Expression ')' - | 'SHA512' '(' Expression ')' - | 'COALESCE' ExpressionList - | 'IF' '(' Expression ',' Expression ',' Expression ')' - | 'STRLANG' '(' Expression ',' Expression ')' - | 'STRDT' '(' Expression ',' Expression ')' - | 'sameTerm' '(' Expression ',' Expression ')' - | 'isIRI' '(' Expression ')' - | 'isURI' '(' Expression ')' - | 'isBLANK' '(' Expression ')' - | 'isLITERAL' '(' Expression ')' - | 'isNUMERIC' '(' Expression ')' + | UCASE '(' Expression ')' + | LCASE '(' Expression ')' + | ENCODE_FOR_URI '(' Expression ')' + | CONTAINS '(' Expression ',' Expression ')' + | STRSTARTS '(' Expression ',' Expression ')' + | STRENDS '(' Expression ',' Expression ')' + | STRBEFORE '(' Expression ',' Expression ')' + | STRAFTER '(' Expression ',' Expression ')' + | YEAR '(' Expression ')' + | MONTH '(' Expression ')' + | DAY '(' Expression ')' + | HOURS '(' Expression ')' + | MINUTES '(' Expression ')' + | SECONDS '(' Expression ')' + | TIMEZONE '(' Expression ')' + | TZ '(' Expression ')' + | NOW Nil + | UUID Nil + | STRUUID Nil + | MD5 '(' Expression ')' + | SHA1 '(' Expression ')' + | SHA256 '(' Expression ')' + | SHA384 '(' Expression ')' + | SHA512 '(' Expression ')' + | COALESCE ExpressionList + | IF '(' Expression ',' Expression ',' Expression ')' + | STRLANG '(' Expression ',' Expression ')' + | STRDT '(' Expression ',' Expression ')' + | SAMETERM '(' Expression ',' Expression ')' + | ISIRI '(' Expression ')' + | ISURI '(' Expression ')' + | ISBLANK '(' Expression ')' + | ISLITERAL '(' Expression ')' + | ISNUMERIC '(' Expression ')' | RegexExpression | ExistsFunc | NotExistsFunc ) } Aggregate { - ( 'COUNT' '(' 'DISTINCT'? ( '*' | Expression ) ')' - | 'SUM' '(' 'DISTINCT'? Expression ')' - | 'MIN' '(' 'DISTINCT'? Expression ')' - | 'MAX' '(' 'DISTINCT'? Expression ')' - | 'AVG' '(' 'DISTINCT'? Expression ')' - | 'SAMPLE' '(' 'DISTINCT'? Expression ')' - | 'GROUP_CONCAT' '(' 'DISTINCT'? Expression ( ';' 'SEPARATOR' '=' String )? ')' ) + ( COUNT '(' DISTINCT? ( '*' | Expression ) ')' + | SUM '(' DISTINCT? Expression ')' + | MIN '(' DISTINCT? Expression ')' + | MAX '(' DISTINCT? Expression ')' + | AVG '(' DISTINCT? Expression ')' + | SAMPLE '(' DISTINCT? Expression ')' + | GROUP_CONCAT '(' DISTINCT? Expression ( ';' SEPARATOR '=' String )? ')' ) } String { @@ -279,27 +232,27 @@ String { } ExpressionList { - ( NIL | "(" Expression ("," Expression)* ")" ) + ( Nil | "(" Expression ("," Expression)* ")" ) } SubstringExpression { - 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')' + SUBSTR '(' Expression ',' Expression ( ',' Expression )? ')' } StrReplaceExpression { - 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')' + REPLACE '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')' } RegexExpression { - 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')' + REGEX '(' Expression ',' Expression ( ',' Expression )? ')' } ExistsFunc { - 'EXISTS' GroupGraphPattern + EXISTS GroupGraphPattern } NotExistsFunc { - 'NOT' 'EXISTS' GroupGraphPattern + NOT EXISTS GroupGraphPattern } GroupGraphPattern { @@ -311,7 +264,7 @@ SubSelect { } WhereClause { - 'WHERE'? GroupGraphPattern + WHERE? GroupGraphPattern } SolutionModifier { @@ -319,39 +272,39 @@ SolutionModifier { } GroupClause { - 'GROUP' 'BY' GroupCondition+ + GROUP BY GroupCondition+ } GroupCondition { - ( BuiltInCall | FunctionCall | '(' Expression ( 'AS' Var )? ')' | Var ) + ( BuiltInCall | FunctionCall | '(' Expression ( AS Var )? ')' | Var ) } FunctionCall { - iri ArgList + Iri ArgList } ArgList { - ( NIL | '(' 'DISTINCT'? Expression ( ',' Expression )* ')' ) + ( Nil | '(' DISTINCT? Expression ( ',' Expression )* ')' ) } HavingClause { - 'HAVING' HavingCondition+ + HAVING HavingCondition+ } HavingCondition { Constraint } -OrderClause { - 'ORDER' 'BY' OrderCondition+ +Constraint { + ( BrackettedExpression | BuiltInCall | FunctionCall ) } -OrderCondition { - ( ( 'ASC' | 'DESC' ) BrackettedExpression ) | ( Constraint | Var ) +OrderClause { + ORDER BY OrderCondition+ } -Constraint { - ( BrackettedExpression | BuiltInCall | FunctionCall ) +OrderCondition { + ( ( ASC | DESC ) BrackettedExpression ) | ( Constraint | Var ) } LimitOffsetClauses { @@ -359,15 +312,15 @@ LimitOffsetClauses { } LimitClause { - 'LIMIT' INTEGER+ + LIMIT Integer+ } OffsetClause { - 'OFFSET' INTEGER+ + OFFSET Integer+ } ValuesClause { - ( 'VALUES' DataBlock )? + ( VALUES DataBlock )? } DataBlock { @@ -379,15 +332,15 @@ InlineDataOneVar { } InlineDataFull { - ( NIL | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | NIL )* '}' + ( Nil | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | Nil )* '}' } DataBlockValue { - ( iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF' ) + ( Iri | RDFLiteral | NumericLiteral | BooleanLiteral | UNDEF ) } RDFLiteral { - String ( LANGTAG | ( '^^' iri ) )? + String ( Langstag | ( '^^' Iri ) )? } NumericLiteral { @@ -395,19 +348,19 @@ NumericLiteral { } NumericLiteralUnsigned { - ( INTEGER | DECIMAL | DOUBLE ) + ( Integer | Decimal | Double ) } NumericLiteralPositive { - ( INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE ) + ( IntegerPositive | DecimalPositive | DoublePositive ) } NumericLiteralNegative { - ( INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE ) + ( IntegerNegative | DecimalNegative | DoubleNegative ) } BooleanLiteral { - ( 'true' | 'false' ) + ( TRUE | FALSE ) } GroupGraphPatternSub { @@ -419,7 +372,7 @@ TriplesBlock { } TriplesSameSubjectPath { - ( VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath ) + VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath } VarOrTerm { @@ -427,15 +380,15 @@ VarOrTerm { } GraphTerm { - ( iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL ) + ( Iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | Nil ) } BlankNode { - ( BlankNodeLabel | ANON ) + ( BlankNodeLabel | Anon ) } BlankNodeLabel { - "_:" blankNodeValue? + "_:" BlankNodeValue? } PropertyListPathNotEmpty { @@ -467,15 +420,15 @@ PathEltOrInverse { } PathPrimary { - ( iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')' ) + ( Iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')' ) } PathNegatedPropertySet { - PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')' + ( PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')' ) } PathOneInPropertySet { - ( iri | 'a' | '^' ( iri | 'a' ) ) + ( Iri | 'a' | '^' ( Iri | 'a' ) ) } PathMod { @@ -495,11 +448,11 @@ ObjectPath { } GraphNodePath { - VarOrTerm | TriplesNodePath + ( VarOrTerm | TriplesNodePath ) } TriplesNodePath { - CollectionPath | BlankNodePropertyListPath + ( CollectionPath | BlankNodePropertyListPath ) } BlankNodePropertyListPath { @@ -543,7 +496,7 @@ Verb { } VarOrIri { - ( Var | iri ) + ( Var | Iri ) } PropertyListPath { @@ -551,47 +504,47 @@ PropertyListPath { } GraphPatternNotTriples { - GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData + ( GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData ) } GroupOrUnionGraphPattern { - GroupGraphPattern ( 'UNION' GroupGraphPattern )* + GroupGraphPattern ( UNION GroupGraphPattern )* } OptionalGraphPattern { - 'OPTIONAL' GroupGraphPattern + OPTIONAL GroupGraphPattern } MinusGraphPattern { - 'MINUS' GroupGraphPattern + MINUS GroupGraphPattern } GraphGraphPattern { - 'GRAPH' VarOrIri GroupGraphPattern + GRAPH VarOrIri GroupGraphPattern } ServiceGraphPattern { - 'SERVICE' 'SILENT'? VarOrIri GroupGraphPattern + SERVICE SILENT? VarOrIri GroupGraphPattern } Filter { - 'FILTER' Constraint + FILTER Constraint } Bind { - 'BIND' '(' Expression 'AS' Var ')' + BIND '(' Expression AS Var ')' } InlineData { - 'VALUES' DataBlock + VALUES DataBlock } iriOrFunction { - iri ArgList? + Iri ArgList? } DatasetClause { - 'FROM' ( DefaultGraphClause | NamedGraphClause ) + FROM ( DefaultGraphClause | NamedGraphClause ) } DefaultGraphClause { @@ -599,13 +552,82 @@ DefaultGraphClause { } NamedGraphClause { - 'NAMED' SourceSelector + NAMED SourceSelector } SourceSelector { - iri + Iri +} + +ConstructQuery { + CONSTRUCT ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* WHERE '{' TriplesTemplate? '}' SolutionModifier ) +} + +ConstructTemplate { + '{' ConstructTriples? '}' +} + +ConstructTriples { + TriplesSameSubject ( '.' ConstructTriples? )? +} + +TriplesSameSubject { + VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList +} + +PropertyList { + PropertyListNotEmpty? +} + +TriplesTemplate { + TriplesSameSubject ( '.' TriplesTemplate? )? +} + +DescribeQuery { + DESCRIBE ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier +} + +AskQuery { + ASK DatasetClause* WhereClause SolutionModifier +} + +GraphRefAll { + ( GraphRef | DEFAULT | NAMED | ALL ) +} + +GraphOrDefault { + DEFAULT | GRAPH? Iri +} + +QuadData { + '{' Quads '}' +} + +Quads { + TriplesTemplate? ( QuadsNotTriples '.'? TriplesTemplate? )* +} + +QuadsNotTriples { + GRAPH VarOrIri '{' TriplesTemplate? '}' +} + +QuadPattern { + '{' Quads '}' +} + +DeleteClause { + DELETE QuadPattern +} + +InsertClause { + INSERT QuadPattern +} + +UsingClause { + USING ( Iri | NAMED Iri ) } + @skip { space | Comment* } @tokens { @@ -616,21 +638,12 @@ SourceSelector { Comment { "#" ![\n]* } - - IriRef { - "<" (![<>"{}|^`\\\x00-\x20])* ">" - } - - iri { - IriRef | PrefixedName + Keyword { + $[_a-zA-Z\u00A1-\u00ff]+ } - PrefixedName { - PnameLn | Namespace - } - - PnameLn { - Namespace PnLocal + IriRef { + "<" (![<>"{}|^`\\\x00-\x20])* ">" } Namespace { @@ -638,27 +651,27 @@ SourceSelector { } PnPrefix { - $[a-z]? + $[a-z] | $[A-Z] } - PN_CHARS_BASE { - ($[A-Z] | $[a-z]) + Var { + $[?$] VarName } - Var { - $[?$] VARNAME + VarName { + ( pn_chars_u | $[0-9] ) ( pn_chars_u | $[0-9] | $[\u00B7] | $[\u0300-\u036F] | $[\u203F-\u2040] )* } - VARNAME { - ( PN_CHARS_U | $[0-9] ) ( PN_CHARS_U | $[0-9] | $[\u00B7] | $[\u0300-\u036F] | $[\u203F-\u2040] )* + pn_chars_u { + ( pn_chars_base | '_' ) } - PN_CHARS_U { - ( PN_CHARS_BASE | '_' ) + pn_chars_base { + $[A-Z] | $[a-z] } stringLiteral1 { - "'" (![\x27\x5C\x0A\x0D] | Echar)* "'" + "'" (![\x27\x5C\x0A\x0D] | Echar)* "'" } stringLiteral2 { @@ -677,90 +690,125 @@ SourceSelector { "\\\\" $[tbnrf\\"'] } - NIL { + Nil { "(" ("\\x20" | "\\x09" | "\\x0D" | "\\x0A")* ")" } + Iri { + IriRef | PrefixedName + } + + PrefixedName { + PnameLn | Namespace + } + + PnameLn { + Namespace PnLocal + } + PnLocal { - (PN_CHARS_U | "\\:" | $[0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )? + (pn_chars_u | "\\:" | $[0-9] | plx ) ((pn_chars | '.' | ':' | plx)* (pn_chars | ':' | plx) )? } - PLX { - (PERCENT | PN_LOCAL_ESC) + plx { + (percent | pn_local_esc) } - PERCENT { - "%" HEX HEX + percent { + "%" hex hex } - HEX { + hex { $[0-9] | $[A-F] | $[a-f] } - - PN_LOCAL_ESC { + pn_local_esc { "\\" } - PN_CHARS { - ( PN_CHARS_U | '-' | $[0-9] | $[\u00B7] | $[\u0300-\u036F] | $[\u203F-\u2040] ) + pn_chars { + ( pn_chars_u | '-' | $[0-9] | $[\u00B7] | $[\u0300-\u036F] | $[\u203F-\u2040] ) } - @precedence { INTEGER, DECIMAL, DOUBLE, ".", blankNodeValue } - @precedence { INTEGER_POSITIVE, DECIMAL_POSITIVE, DOUBLE_POSITIVE, "+" } - @precedence { INTEGER_NEGATIVE, DECIMAL_NEGATIVE, DOUBLE_NEGATIVE, "-" } - @precedence { iri, "false", "true", "a", blankNodeValue, space } - @precedence { Var, "?" } - - INTEGER { + Integer { @digit+ } - DECIMAL { + Decimal { @digit* "." @digit+ } - DOUBLE { - @digit+ "." @digit* EXPONENT | "." (@digit)+ EXPONENT | (@digit)+ EXPONENT + Double { + @digit+ "." @digit* Exponent | "." (@digit)+ Exponent | (@digit)+ Exponent } - INTEGER_POSITIVE { - "+" INTEGER + + IntegerPositive { + "+" Integer } - DECIMAL_POSITIVE { - "+" DECIMAL + DecimalPositive { + "+" Decimal } - DOUBLE_POSITIVE { - "+" DOUBLE + DoublePositive { + "+" Double } - INTEGER_NEGATIVE { - "-" INTEGER + IntegerNegative { + "-" Integer } - DECIMAL_NEGATIVE { - "-" DECIMAL + DecimalNegative { + "-" Decimal } - DOUBLE_NEGATIVE { - "-" DOUBLE + DoubleNegative { + "-" Double } - EXPONENT { + Exponent { $[eE] $[+-]? @digit+ } - LANGTAG { + Langstag { "@" @asciiLetter+ ("-" ( @asciiLowercase | @asciiUppercase | @digit)+)* } - ANON { + BlankNodeValue { + ( $[A-Z] | $[a-z] | $[\u00C0-\u00D6] | $[\u00D8-\u00F6] | $[\u00F8-\u02FF] | $[\u0370-\u037D] | $[\u037F-\u1FFF] | $[\u200C-\u200D] | $[\u2070-\u218F] | $[\u2C00-\u2FEF] | $[\u3001-\uD7FF] | $[\uF900-\uFDCF] | $[\uFDF0-\uFFFD] | "_" | $[0-9] )+ + } + + Anon { "[" ("\\x20" | "\\x09" | "\\x0D" | "\\x0A")* "]" } - blankNodeValue { - $[A-Z] | $[a-z] | $[\u00C0-\u00D6] | $[\u00D8-\u00F6] | $[\u00F8-\u02FF] | $[\u0370-\u037D] | $[\u037F-\u1FFF] | $[\u200C-\u200D] | $[\u2070-\u218F] | $[\u2C00-\u2FEF] | $[\u3001-\uD7FF] | $[\uF900-\uFDCF] | $[\uFDF0-\uFFFD] | "_" | $[0-9] + @precedence { Iri, "a" , "_:", space, Keyword, BlankNodeValue } + @precedence { + DoublePositive, DecimalPositive, IntegerPositive, Double, Decimal, Integer, "+", ".", BlankNodeValue + } + + @precedence { + DoubleNegative, DecimalNegative, IntegerNegative, Double, Decimal, Integer, "-", ".", BlankNodeValue } + + @precedence { + Var "?" + } + + "_:" "{" "}" "." "," ";" } + + +@external specialize { Keyword } caseInsensitive from "./tokens" { + BASE, PREFIX, SELECT, CONSTRUCT, DESCRIBE, WHERE, DISTINCT, REDUCED, STR, LANG, LANGMATCHES, DATATYPE, ASK, BOUND, IRI, URI, BNODE, RAND, ABS, CEIL, FLOOR, ROUND, CONCAT, STRLEN, UCASE, LCASE, + ENCODE_FOR_URI, CONTAINS, STRSTARTS, STRENDS, STRBEFORE, STRAFTER, YEAR, MONTH, DAY, + HOURS, MINUTES, SECONDS, TIMEZONE, TZ, NOW, UUID, STRUUID, MD5, SHA1, SHA256, SHA384, + SHA512, COALESCE, IF, STRLANG, STRDT, SAMETERM, ISIRI, ISURI, ISBLANK, ISLITERAL, + ISNUMERIC, COUNT, SUM, MIN, MAX, AVG, SAMPLE, GROUP_CONCAT, SEPARATOR, SUBSTR, REPLACE, + REGEX, EXISTS, NOT, IN, GROUP, BY, HAVING, ORDER, ASC, DESC, LIMIT, OFFSET, VALUES, UNDEF, + UNION, OPTIONAL, MINUS, GRAPH, SERVICE, SILENT, FILTER, BIND, AS, FROM, NAMED, TRUE, FALSE, LOAD, INTO, TO, CLEAR, DROP, CREATE, ADD, MOVE, COPY, INSERT, DATA, DELETE, WITH, DEFAULT, ALL, USING +} + +@external propSource highlight from "./highlight" + diff --git a/src/tokens.js b/src/tokens.js new file mode 100644 index 0000000..b65554a --- /dev/null +++ b/src/tokens.js @@ -0,0 +1,10 @@ +import * as tokens from "./parser.terms.js" + +/** + * Keywords are matched in a case-insensitive manner with the exception + * of the keyword 'a' which, in line with Turtle and N3, is used in place + * of the IRI rdf:type (in full, http://www.w3.org/1999/02/22-rdf-syntax-ns#type). + */ +export const caseInsensitive = (value, stack) => { + return tokens[value.toUpperCase()] || -1; +}; \ No newline at end of file diff --git a/test/cases.txt b/test/cases.txt index 47c2aa5..66e3c50 100644 --- a/test/cases.txt +++ b/test/cases.txt @@ -7,17 +7,21 @@ SELECT * WHERE { ==> -QueryUnit( +Unit( Query( Prologue( PrefixDecl( + PREFIX Namespace, IriRef ) ) SelectQuery( - SelectClause + SelectClause ( + SELECT + ) WhereClause( + WHERE GroupGraphPattern( GroupGraphPatternSub ( TriplesBlock ( @@ -47,7 +51,8 @@ QueryUnit( SolutionModifier ( LimitOffsetClauses ( LimitClause ( - INTEGER + LIMIT + Integer ) ) )