diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05345dd..c7346a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Run tests run: ruby --version; bundle exec rspec spec || $ALLOW_FAILURES - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v1.1.2 + uses: coverallsapp/github-action@v2 if: "matrix.ruby == '3.0'" with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index fa1144d..07e55f3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [EBNF][] parser and generic parser generator. -[![Gem Version](https://badge.fury.io/rb/ebnf.png)](https://badge.fury.io/rb/ebnf) +[![Gem Version](https://badge.fury.io/rb/ebnf.svg)](https://badge.fury.io/rb/ebnf) [![Build Status](https://github.com/dryruby/ebnf/workflows/CI/badge.svg?branch=develop)](https://github.com/dryruby/ebnf/actions?query=workflow%3ACI) [![Coverage Status](https://coveralls.io/repos/dryruby/ebnf/badge.svg?branch=develop)](https://coveralls.io/r/dryruby/ebnf?branch=develop) [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf) diff --git a/VERSION b/VERSION index f90b1af..0bee604 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.2 +2.3.3 diff --git a/etc/turtle.html b/etc/turtle.html index ea5e211..9cebd1f 100644 --- a/etc/turtle.html +++ b/etc/turtle.html @@ -1,467 +1,388 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
[1]turtleDoc::= -statement* -
[2]statement::= -directive | triples "." -
[3]directive::= -prefixID -| base -| sparqlPrefix -| sparqlBase -
[4]prefixID::= -"@prefix" PNAME_NS IRIREF "." -
[5]base::= -"@base" IRIREF "." -
[28s]sparqlPrefix::= -SPARQL_PREFIX PNAME_NS IRIREF -
[29s]sparqlBase::= -SPARQL_BASE IRIREF -
[6]triples::= -subject predicateObjectList -| blankNodePropertyList predicateObjectList? -
[7]predicateObjectList::= -verb -objectList -(";" (verb objectList)?)* -
[8]objectList::= -object ("," object)* -
[9]verb::= -predicate | "a" -
[10]subject::= -iri | BlankNode | collection -
[11]predicate::= -iri -
[12]object::= -iri -| BlankNode -| collection -| blankNodePropertyList -| literal -
[13]literal::= -RDFLiteral -| NumericLiteral -| BooleanLiteral -
[14]blankNodePropertyList::= -"[" predicateObjectList "]" -
[15]collection::= -"(" object* ")" -
[16]NumericLiteral::= -INTEGER | DECIMAL | DOUBLE -
[128s]RDFLiteral::= -String (LANGTAG | "^^" iri)? -
[133s]BooleanLiteral::= -"true" | "false" -
[17]String::= -STRING_LITERAL_QUOTE -| STRING_LITERAL_SINGLE_QUOTE -| STRING_LITERAL_LONG_SINGLE_QUOTE -| STRING_LITERAL_LONG_QUOTE -
[135s]iri::= -IRIREF | PrefixedName -
[136s]PrefixedName::= -PNAME_LN | PNAME_NS -
[137s]BlankNode::= -BLANK_NODE_LABEL | ANON -
[18]IRIREF::= -"<" -[^#x00-#x20<>"{}|^`]#x20|#x20UCHAR)*#x20'>'] -
[139s]PNAME_NS::= -PN_PREFIX? ":" -
[140s]PNAME_LN::= -PNAME_NS PN_LOCAL -
[141s]BLANK_NODE_LABEL::= -"_:" -(PN_CHARS_U | [0-9]) -(PN_CHARS | ".")* PN_CHARS? -
[144s]LANGTAG::= -"@" ([a-zA-Z])+ ("-" ([a-zA-Z0-9])+)* -
[19]INTEGER::= -([+-])? ([0-9])+ -
[20]DECIMAL::= -([+-])? (([0-9])* "." ([0-9])+) -
[21]DOUBLE::= -([+-])? -(([0-9])+ "." ([0-9])* EXPONENT | "." ([0-9])+ EXPONENT | ([0-9])+ EXPONENT) -
[154s]EXPONENT::= -[eE] ([+-])? ([0-9])+ -
[22]STRING_LITERAL_QUOTE::= -'"' -([^#x22#x5C#xA#xD] | ECHAR | UCHAR)* -'"' -
[23]STRING_LITERAL_SINGLE_QUOTE::= -"'" -([^#x27#x5C#xA#xD] | ECHAR | UCHAR)* -"'" -
[24]STRING_LITERAL_LONG_SINGLE_QUOTE::= -"'''" -(("'" | "''")? [^']#x20|#x20ECHAR#x20|#x20UCHAR#x20)#x20)*#x20"'''"]) -
[25]STRING_LITERAL_LONG_QUOTE::= -'"""' -(('"' | '""')? [^"]#x20|#x20ECHAR#x20|#x20UCHAR#x20)#x20)*#x20'"""']) -
[26]UCHAR::= -"u" HEX HEX HEX HEX -| "U" HEX HEX HEX HEX HEX HEX HEX HEX -
[159s]ECHAR::= -"\" [tbnrf"'] -
[28t]SPARQL_PREFIX::= -[Pp] [Rr] [Ee] [Ff] [Ii] [Xx] -
[29t]SPARQL_BASE::= -[Bb] [Aa] [Ss] [Ee] -
[161s]WS::= -#x20 | #x9 | #xD | #xA -
[162s]ANON::= -"[" WS* "]" -
[163s]PN_CHARS_BASE::= -[A-Z] -| [a-z] -| [#x00C0-#x00D6] -| [#x00D8-#x00F6] -| [#x00F8-#x02FF] -| [#x0370-#x037D] -| [#x037F-#x1FFF] -| [#x200C-#x200D] -| [#x2070-#x218F] -| [#x2C00-#x2FEF] -| [#x3001-#xD7FF] -| [#xF900-#xFDCF] -| [#xFDF0-#xFFFD] -| [#x10000-#xEFFFF] -
[164s]PN_CHARS_U::= -PN_CHARS_BASE | "_" -
[166s]PN_CHARS::= -PN_CHARS_U -| "-" -| [0-9] -| #x00B7 -| [#x0300-#x036F] -| [#x203F-#x2040] -
[167s]PN_PREFIX::= -PN_CHARS_BASE -(PN_CHARS | ".")* PN_CHARS? -
[168s]PN_LOCAL::= -(PN_CHARS_U | ":" | [0-9] | PLX) -(PN_CHARS | "." | ":" | PLX)* (PN_CHARS | ":" | PLX)? -
[169s]PLX::= -PERCENT | PN_LOCAL_ESC -
[170s]PERCENT::= -"%" HEX HEX -
[171s]HEX::= -[0-9] | [A-F] | [a-f] -
[172s]PN_LOCAL_ESC::= -"\" -("_" | "~" | "." | "-" | #x21 | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "=" | "/" | "?" | "#" | "@" | "%") -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[1]turtleDoc::=statement*
[2]statement::=directive | (triples ".")
[3]directive::=prefixID | base | sparqlPrefix | sparqlBase
[4]prefixID::="@prefix" PNAME_NS IRIREF "."
[5]base::="@base" IRIREF "."
[28s]sparqlPrefix::=SPARQL_PREFIX PNAME_NS IRIREF
[29s]sparqlBase::=SPARQL_BASE IRIREF
[6]triples::=(subject predicateObjectList) | (blankNodePropertyList predicateObjectList?)
[7]predicateObjectList::=verb objectList (";" (verb objectList)?)*
[8]objectList::=object ("," object)*
[9]verb::=predicate | "a"
[10]subject::=iri | BlankNode | collection
[11]predicate::=iri
[12]object::=iri | BlankNode | collection | blankNodePropertyList | literal
[13]literal::=RDFLiteral | NumericLiteral | BooleanLiteral
[14]blankNodePropertyList::="[" predicateObjectList "]"
[15]collection::="(" object* ")"
[16]NumericLiteral::=INTEGER | DECIMAL | DOUBLE
[128s]RDFLiteral::=String (LANGTAG | ("^^" iri))?
[133s]BooleanLiteral::="true" | "false"
[17]String::=STRING_LITERAL_QUOTE | STRING_LITERAL_SINGLE_QUOTE | STRING_LITERAL_LONG_SINGLE_QUOTE | STRING_LITERAL_LONG_QUOTE
[135s]iri::=IRIREF | PrefixedName
[136s]PrefixedName::=PNAME_LN | PNAME_NS
[137s]BlankNode::=BLANK_NODE_LABEL | ANON
@terminals# Productions for terminals
[18]IRIREF::="<" ([^<>"{}|^`]-[#x00-#x20] | UCHAR)* ">"
[139s]PNAME_NS::=PN_PREFIX? ":"
[140s]PNAME_LN::=PNAME_NS PN_LOCAL
[141s]BLANK_NODE_LABEL::="_:" (PN_CHARS_U | [0-9]) ((PN_CHARS | ".")* PN_CHARS)?
[144s]LANGTAG::="@" [a-zA-Z]+ ("-" [a-zA-Z0-9]+)*
[19]INTEGER::=[+-]? [0-9]+
[20]DECIMAL::=[+-]? ([0-9]* "." [0-9]+)
[21]DOUBLE::=[+-]? (([0-9]+ "." [0-9]* EXPONENT) | ("." [0-9]+ EXPONENT) | ([0-9]+ EXPONENT))
[154s]EXPONENT::=[eE] [+-]? [0-9]+
[22]STRING_LITERAL_QUOTE::='"' ([^>"#x5C#x0A#x0D] | ECHAR | UCHAR)* '"'
[23]STRING_LITERAL_SINGLE_QUOTE::="'" ([^#x27#x5C#x0A#x0D] | ECHAR | UCHAR)* "'"
[24]STRING_LITERAL_LONG_SINGLE_QUOTE::="'''" (("'" | "''")? [^']#x20|#x20ECHAR#x20|#x20UCHAR#x20)#x20)*#x20"'''"])
[25]STRING_LITERAL_LONG_QUOTE::='"""' (('"' | '""')? [^"]#x20|#x20ECHAR#x20|#x20UCHAR#x20)#x20)*#x20'"""'])
[26]UCHAR::=("u" HEX HEX HEX HEX) | ("U" HEX HEX HEX HEX HEX HEX HEX HEX)
[159s]ECHAR::="\" [tbnrf"']
[28t]SPARQL_PREFIX::=[Pp] [Rr] [Ee] [Ff] [Ii] [Xx]
[29t]SPARQL_BASE::=[Bb] [Aa] [Ss] [Ee]
[161s]WS::=#x20 | #x09 | #x0D | #x0A
[162s]ANON::="[" WS* "]"
[163s]PN_CHARS_BASE::=[A-Z]
|[a-z]
|[#xC0-#xD6]
|[#xD8-#xF6]
|[#xF8-#x02FF]
|[#x0370-#x037D]
|[#x037F-#x1FFF]
|[#x200C-#x200D]
|[#x2070-#x218F]
|[#x2C00-#x2FEF]
|[#x3001-#xD7FF]
|[#xF900-#xFDCF]
|[#xFDF0-#xFFFD]
|[#x00010000-#x000EFFFF]
[164s]PN_CHARS_U::=PN_CHARS_BASE | "_"
[166s]PN_CHARS::=PN_CHARS_U | "-" | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
[167s]PN_PREFIX::=PN_CHARS_BASE ((PN_CHARS | ".")* PN_CHARS)?
[168s]PN_LOCAL::=(PN_CHARS_U | ":" | [0-9] | PLX) ((PN_CHARS | "." | ":" | PLX)* (PN_CHARS | ":" | PLX))?
[169s]PLX::=PERCENT | PN_LOCAL_ESC
[170s]PERCENT::="%" HEX HEX
[171s]HEX::=[0-9A-Fa-f]
[172s]PN_LOCAL_ESC::="\" ("_" | "~" | "." | "-" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "=" | "/" | "?" | "#" | "@" | "%")
+ diff --git a/lib/ebnf/native.rb b/lib/ebnf/native.rb index c3fbb43..8ab9cff 100644 --- a/lib/ebnf/native.rb +++ b/lib/ebnf/native.rb @@ -289,7 +289,8 @@ def terminal(s) l, s = s[1..-1].split(m.rstrip, 2) [Unescape.unescape_string(l), s] when '[' # RANGE, O_RANGE - l, s = s[1..-1].split(/(?<=[^\\])\]/, 2) + # Includes RANGE and O_RANGE which can't include a ']' + l, s = s[1..-1].split(']', 2) [[:range, Unescape.unescape_string(l)], s] when '#' # HEX s.match(/(#x\h+)(.*)$/) diff --git a/lib/ebnf/writer.rb b/lib/ebnf/writer.rb index 5de5d91..e7b28df 100644 --- a/lib/ebnf/writer.rb +++ b/lib/ebnf/writer.rb @@ -246,14 +246,14 @@ def format_ebnf(expr, sep: nil, embedded: false) format_ebnf_string(expr, expr.include?('"') ? "'" : '"') end parts = { - alt: (@options[:html] ? "| " : "| "), - diff: (@options[:html] ? "- " : "- "), - star: (@options[:html] ? "* " : "*"), - plus: (@options[:html] ? "+ " : "+"), - opt: (@options[:html] ? "? " : "?") + alt: (@options[:html] ? %(| ) : "| "), + diff: (@options[:html] ? %(- ) : "- "), + star: (@options[:html] ? %(*) : "*"), + plus: (@options[:html] ? %(+) : "+"), + opt: (@options[:html] ? %(?) : "?") } - lparen = (@options[:html] ? "( " : "(") - rparen = (@options[:html] ? ") " : ")") + lparen = (@options[:html] ? %[(] : "(") + rparen = (@options[:html] ? %[)] : ")") case expr.first when :istr @@ -323,8 +323,8 @@ def format_ebnf_char(c) # Format a range def format_ebnf_range(string) - lbrac = (@options[:html] ? "[ " : "[") - rbrac = (@options[:html] ? "] " : "]") + lbrac = (@options[:html] ? %([) : "[") + rbrac = (@options[:html] ? %(]) : "]") buffer = lbrac s = StringScanner.new(string) @@ -412,15 +412,15 @@ def format_abnf(expr, sep: nil, embedded: false, sensitive: true) end end parts = { - alt: (@options[:html] ? "/" : "/ "), - star: (@options[:html] ? "*" : "*"), - plus: (@options[:html] ? "+" : "1*"), - opt: (@options[:html] ? "?" : "?") + alt: (@options[:html] ? %(/) : "/ "), + star: (@options[:html] ? %(*) : "*"), + plus: (@options[:html] ? %(+) : "1*"), + opt: (@options[:html] ? %(?) : "?") } - lbrac = (@options[:html] ? "[ " : "[") - rbrac = (@options[:html] ? "] " : "]") - lparen = (@options[:html] ? "( " : "(") - rparen = (@options[:html] ? ") " : ")") + lbrac = (@options[:html] ? %([) : "[") + rbrac = (@options[:html] ? %(]) : "]") + lparen = (@options[:html] ? %[(] : "(") + rparen = (@options[:html] ? %[)] : ")") case expr.first when :istr @@ -597,11 +597,11 @@ def format_isoebnf(expr, sep: nil, embedded: false) end end parts = { - alt: (@options[:html] ? "| " : "| "), - diff: (@options[:html] ? "- " : "- "), + alt: (@options[:html] ? %(| ) : "| "), + diff: (@options[:html] ? %(- ) : "- "), } - lparen = (@options[:html] ? "( " : "(") - rparen = (@options[:html] ? ") " : ")") + lparen = (@options[:html] ? %[(] : "(") + rparen = (@options[:html] ? %[)] : ")") case expr.first when :istr @@ -709,6 +709,7 @@ def format_isoebnf_range(string) end ERB_DESC = %q( + <% for rule in @rules %> diff --git a/spec/writer_spec.rb b/spec/writer_spec.rb index dd76b64..d507333 100644 --- a/spec/writer_spec.rb +++ b/spec/writer_spec.rb @@ -107,6 +107,10 @@ %{[2] Prolog ::= BaseDecl? PrefixDecl*}, %{[2] Prolog ::= BaseDecl? PrefixDecl*\n} ], + backslash: [ + %{LHS ::= [^'\] | ECHAR}, + %{LHS ::= [^'\] | ECHAR\n} + ] }.each do |title, (grammar, plain)| context title do subject {EBNF::Base.new(grammar, format: :native).ast}