From 7fd5f4c2bb884e9649ab84cec5d68f67c8795302 Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Thu, 28 Nov 2019 16:18:47 +0100 Subject: [PATCH 01/15] Add a Cypher (Neo4j) lexer --- lib/rouge/demos/cypher | 17 +++++++ lib/rouge/lexers/cypher.rb | 94 ++++++++++++++++++++++++++++++++++ spec/lexers/cypher_spec.rb | 18 +++++++ spec/visual/samples/cypher | 100 +++++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 lib/rouge/demos/cypher create mode 100644 lib/rouge/lexers/cypher.rb create mode 100644 spec/lexers/cypher_spec.rb create mode 100644 spec/visual/samples/cypher diff --git a/lib/rouge/demos/cypher b/lib/rouge/demos/cypher new file mode 100644 index 0000000000..94963e9f23 --- /dev/null +++ b/lib/rouge/demos/cypher @@ -0,0 +1,17 @@ +// Cypher Mode for Rouge +CREATE (john:Person {name: 'John'}) +CREATE (joe:Person {name: 'Joe'}) +CREATE (steve:Person {name: 'Steve'}) +CREATE (sara:Person {name: 'Sara'}) +CREATE (maria:Person {name: 'Maria'}) +CREATE (john)-[:FRIEND]->(joe)-[:FRIEND]->(steve) +CREATE (john)-[:FRIEND]->(sara)-[:FRIEND]->(maria) + +MATCH (user)-[:friend]->(follower) +WHERE user.name IN ['Joe', 'John', 'Sara', 'Maria', 'Steve'] AND follower.name =~ 'S.*' +RETURN user.name, follower.name + +MATCH (n {name: 'John'})-[:FRIEND]-(friend) +WITH n, count(friend) AS friendsCount +WHERE friendsCount > 3 +RETURN n, friendsCount \ No newline at end of file diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb new file mode 100644 index 0000000000..79fe9cd002 --- /dev/null +++ b/lib/rouge/lexers/cypher.rb @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true + +module Rouge + module Lexers + class Cypher < RegexLexer + tag 'cypher' + aliases 'cypher' + filenames '*.cypher' + mimetypes 'application/x-cypher-query' + + title "Cypher" + desc 'The Cypher query language (https://neo4j.com/docs/cypher-manual)' + + functions = %w( + ABS ACOS ALLSHORTESTPATHS ASIN ATAN ATAN2 AVG CEIL COALESCE COLLECT COS COT COUNT DATE DEGREES E ENDNODE + EXP EXTRACT FILTER FLOOR HAVERSIN HEAD ID KEYS LABELS LAST LEFT LENGTH LOG LOG10 LOWER LTRIM MAX MIN NODE NODES + PERCENTILECONT PERCENTILEDISC PI RADIANS RAND RANGE REDUCE REL RELATIONSHIP RELATIONSHIPS REPLACE REVERSE RIGHT + ROUND RTRIM SHORTESTPATH SIGN SIN SIZE SPLIT SQRT STARTNODE STDEV STDEVP STR SUBSTRING SUM TAIL TAN TIMESTAMP + TOFLOAT TOINT TOINTEGER TOSTRING TRIM TYPE UPPER + ) + + pedicates = %w( + ALL AND ANY CONTAINS EXISTS HAS IN NONE NOT OR SINGLE XOR + ) + + keywords = %w( + AS ASC ASCENDING ASSERT BY CASE COMMIT CONSTRAINT CREATE CSV CYPHER DELETE DESC DESCENDING DETACH + DISTINCT DROP ELSE END ENDS EXPLAIN FALSE FIELDTERMINATOR FOREACH FROM HEADERS IN INDEX IS JOIN LIMIT LOAD MATCH + MERGE NULL ON OPTIONAL ORDER PERIODIC PROFILE REMOVE RETURN SCAN SET SKIP START STARTS THEN TRUE UNION UNIQUE + UNWIND USING WHEN WHERE WITH CALL YIELD + ) + + state :root do + rule %r/[^\S\n]+/, Text + rule %r(//.*?$), Comment::Single + + rule %r([*+\-<>=&|~%^]), Operator + rule %r/[{}),;\[\]]/, Literal::String::Symbol + + # literal number + rule %r/([_\w\d]+)(:)(\s*)([._\d]+)/ do + groups Name::Label, Literal::String::Delimiter, Text::Whitespace, Literal::Number + end + + # function-like + # - "name(" + # - "name (" + # - "name (" + rule %r/([\w]+)(\s*)(\()/ do |m| + name = m[1].upcase + if functions.include? name + groups Name::Function, Text::Whitespace, Literal::String::Symbol + elsif keywords.include? name + groups Keyword, Text::Whitespace, Literal::String::Symbol + else + groups Name, Text::Whitespace, Literal::String::Symbol + end + end + + rule %r/:[_\w\d]+/, Name::Class + + # number range + rule %r/(-?)(\d+)(\.\.)(-?)(\d+)/ do + groups Literal::String::Symbol, Literal::Number, Literal::String::Symbol, Literal::String::Symbol, Literal::Number + end + + rule %r/(\d+)+/, Literal::Number + + rule %r([._\w\d]+:), Name::Property + + # remaining "(" + rule %r/\(/, Literal::String::Symbol + + rule %r/[._\w\d$]+/ do |m| + match = m[0].upcase + if pedicates.include? match + token Operator::Word + elsif keywords.include? match + token Keyword + else + token Name + end + end + + rule %r/"(\\\\|\\"|[^"])*"/, Str + rule %r/'(\\\\|\\'|[^'])*'/, Str + rule %r/`(\\\\|\\`|[^`])*`/, Str + + rule %r/\n/, Text + end + end + end +end \ No newline at end of file diff --git a/spec/lexers/cypher_spec.rb b/spec/lexers/cypher_spec.rb new file mode 100644 index 0000000000..1d95e2d1e5 --- /dev/null +++ b/spec/lexers/cypher_spec.rb @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true + +describe Rouge::Lexers::Cypher do + let(:subject) { Rouge::Lexers::Cypher.new } + + describe 'guessing' do + include Support::Guessing + + it 'guesses by filename' do + assert_guess :filename => 'foo.cypher' + end + + it 'guesses by mimetype' do + assert_guess :mimetype => 'application/x-cypher-query' + end + end +end diff --git a/spec/visual/samples/cypher b/spec/visual/samples/cypher new file mode 100644 index 0000000000..3edd0712b7 --- /dev/null +++ b/spec/visual/samples/cypher @@ -0,0 +1,100 @@ +// Cypher for Rouge +CREATE (john:Person {name: 'John'}) +CREATE (joe:Person {name: 'Joe'}) +CREATE (steve:Person {name: 'Steve'}) +CREATE (sara:Person {name: 'Sara'}) +CREATE (maria:Person {name: 'Maria'}) +CREATE (john)-[:KNOWS]->(joe)-[:KNOWS]->(steve) +CREATE (john)-[:KNOWS]->(sara)-[:KNOWS]->(maria) + +MATCH (joe { name: 'Joe' })-[:knows*2..2]-(friend_of_friend) +WHERE NOT (joe)-[:knows]-(friend_of_friend) +RETURN friend_of_friend.name, COUNT(*) +ORDER BY COUNT(*) DESC , friend_of_friend.name + +LOAD CSV WITH HEADERS FROM "https://dl.dropboxusercontent.com/u/14493611/movies_setup.csv" AS row +MERGE (m:Movie {title:row.title}) ON CREATE SET m.tagline = row.tagline,m.released=row.released +MERGE (p:Person {name:row.name}) ON CREATE SET p.born = row.born +FOREACH (_ in CASE row.type WHEN "ACTED_IN" then [1] else [] end | + MERGE (p)-[r:ACTED_IN]->(m) ON CREATE SET r.roles = split(row.roles,";")[0..-1] +) +FOREACH (_ in CASE row.type WHEN "DIRECTED" then [1] else [] end | MERGE (p)-[:DIRECTED]->(m)) +FOREACH (_ in CASE row.type WHEN "PRODUCED" then [1] else [] end | MERGE (p)-[:PRODUCED]->(m)) +FOREACH (_ in CASE row.type WHEN "WROTE" then [1] else [] end | MERGE (p)-[:WROTE ]->(m)) +FOREACH (_ in CASE row.type WHEN "REVIEWED" then [1] else [] end | MERGE (p)-[:REVIEWED]->(m)) + +MATCH (n:Person { name: $name }) +RETURN n + +UNWIND $props AS properties +CREATE (n:Person) +SET n = properties +RETURN n + +MATCH (n) +WHERE id(n)= $id +RETURN n.name + +START n=node:people(name = $value) +RETURN n + +MATCH (n) RETURN n // This is an end of line comment + +MATCH (n) WHERE n.property = '//This is NOT a comment' RETURN n + +MATCH (a:Person { name: 'Keanu Reeves' }) +RETURN [(a)-->(b) WHERE b:Movie | b.released] AS years + +// alias with backticks +MATCH (p:Person {born: 1965}) +RETURN p.name AS name, p.born AS `birth year` + +// complex queries +LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/advanced-cypher/movies2.csv' AS row +MERGE (m:Movie {id:toInteger(row.movieId)}) + ON CREATE SET m.title=row.title, m.avgVote=toFloat(row.avgVote), + m.releaseYear=toInteger(row.releaseYear), m.genres=split(row.genres,":") +MERGE (p:Person {id: toInteger(row.personId)}) + ON CREATE SET p.name = row.name, p.born = toInteger(row.birthYear), + p.died = toInteger(row.deathYear) +WITH row, m, p +CALL apoc.do.when(row.personType = 'ACTOR', + "MERGE (p)-[:ACTED_IN {roles: split(coalesce(row.characters,''), ':')}]->(m) + ON CREATE SET p:Actor", + "MERGE (p)-[:DIRECTED]->(m) + ON CREATE SET p:Director", + {row:row, m:m, p:p}) YIELD value AS value +SET p:Person // cannot end query with APOC call + +PROFILE LOAD CSV WITH HEADERS FROM + 'https://data.neo4j.com/advanced-cypher/movies2.csv' AS row +WITH row.movieId as movieId, row.title as title, row.genres as genres, +toInteger(row.releaseYear) as releaseYear, toFloat(row.avgVote) as avgVote, +collect({id: row.personId, name:row.name, born: toInteger(row.birthYear), died:toInteger(row.deathYear),personType: row.personType, roles: split(coalesce(row.characters,""),':')}) as people +MERGE (m:Movie {id:movieId}) + ON CREATE SET m.title=title, m.avgVote=avgVote, + m.releaseYear=releaseYear, m.genres=split(genres,":") +WITH * +UNWIND people as person +MERGE (p:Person {id: person.id}) + ON CREATE SET p.name = person.name, p.born = person.born, p.died = person.died +WITH m, person, p +CALL apoc.do.when(person.personType = 'ACTOR', + "MERGE (p)-[:ACTED_IN {roles: person.roles}]->(m) + ON CREATE SET p:Actor", + "MERGE (p)-[:DIRECTED]->(m) + ON CREATE SET p:Director", + {m:m, p:p, person:person}) YIELD value AS value +RETURN count() // cannot end query with APOC call + +MATCH (m:Movie) +WITH collect(m.title) AS Movies, collect (m.released) AS Released +WITH Movies, Released, +[x IN Released | date().year - x + 1] AS YearsAgo +RETURN Movies, YearsAgo + +MATCH (p:Person)-[rel:ACTED_IN]->(m:Movie {title: 'The Matrix'}) +RETURN p, rel, m + +MATCH (p:Person)-[rel]->(:Movie {title:'The Matrix'}) +RETURN p.name, type(rel) \ No newline at end of file From 481a81b6edeb6c6c2aa6938b2603d1ab5dd06910 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:29:27 +0900 Subject: [PATCH 02/15] Update URL --- lib/rouge/lexers/cypher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 79fe9cd002..54d1ad5eff 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -10,7 +10,7 @@ class Cypher < RegexLexer mimetypes 'application/x-cypher-query' title "Cypher" - desc 'The Cypher query language (https://neo4j.com/docs/cypher-manual)' + desc 'The Cypher query language (neo4j.com/docs/cypher-manual)' functions = %w( ABS ACOS ALLSHORTESTPATHS ASIN ATAN ATAN2 AVG CEIL COALESCE COLLECT COS COT COUNT DATE DEGREES E ENDNODE @@ -91,4 +91,4 @@ class Cypher < RegexLexer end end end -end \ No newline at end of file +end From 49cb720fb642ac8f42437cc2578d31e7c1608757 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:36:58 +0900 Subject: [PATCH 03/15] Use memoising methods --- lib/rouge/lexers/cypher.rb | 55 +++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 54d1ad5eff..876718c8a0 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -12,24 +12,35 @@ class Cypher < RegexLexer title "Cypher" desc 'The Cypher query language (neo4j.com/docs/cypher-manual)' - functions = %w( - ABS ACOS ALLSHORTESTPATHS ASIN ATAN ATAN2 AVG CEIL COALESCE COLLECT COS COT COUNT DATE DEGREES E ENDNODE - EXP EXTRACT FILTER FLOOR HAVERSIN HEAD ID KEYS LABELS LAST LEFT LENGTH LOG LOG10 LOWER LTRIM MAX MIN NODE NODES - PERCENTILECONT PERCENTILEDISC PI RADIANS RAND RANGE REDUCE REL RELATIONSHIP RELATIONSHIPS REPLACE REVERSE RIGHT - ROUND RTRIM SHORTESTPATH SIGN SIN SIZE SPLIT SQRT STARTNODE STDEV STDEVP STR SUBSTRING SUM TAIL TAN TIMESTAMP - TOFLOAT TOINT TOINTEGER TOSTRING TRIM TYPE UPPER - ) - - pedicates = %w( - ALL AND ANY CONTAINS EXISTS HAS IN NONE NOT OR SINGLE XOR - ) - - keywords = %w( - AS ASC ASCENDING ASSERT BY CASE COMMIT CONSTRAINT CREATE CSV CYPHER DELETE DESC DESCENDING DETACH - DISTINCT DROP ELSE END ENDS EXPLAIN FALSE FIELDTERMINATOR FOREACH FROM HEADERS IN INDEX IS JOIN LIMIT LOAD MATCH - MERGE NULL ON OPTIONAL ORDER PERIODIC PROFILE REMOVE RETURN SCAN SET SKIP START STARTS THEN TRUE UNION UNIQUE - UNWIND USING WHEN WHERE WITH CALL YIELD - ) + def self.functions + @functions ||= Set.new %w( + ABS ACOS ALLSHORTESTPATHS ASIN ATAN ATAN2 AVG CEIL COALESCE COLLECT + COS COT COUNT DATE DEGREES E ENDNODE EXP EXTRACT FILTER FLOOR + HAVERSIN HEAD ID KEYS LABELS LAST LEFT LENGTH LOG LOG10 LOWER LTRIM + MAX MIN NODE NODES PERCENTILECONT PERCENTILEDISC PI RADIANS RAND + RANGE REDUCE REL RELATIONSHIP RELATIONSHIPS REPLACE REVERSE RIGHT + ROUND RTRIM SHORTESTPATH SIGN SIN SIZE SPLIT SQRT STARTNODE STDEV + STDEVP STR SUBSTRING SUM TAIL TAN TIMESTAMP TOFLOAT TOINT TOINTEGER + TOSTRING TRIM TYPE UPPER + ) + end + + def self.predicates + @predicates ||= Set.new %w( + ALL AND ANY CONTAINS EXISTS HAS IN NONE NOT OR SINGLE XOR + ) + end + + def self.keywords + @keywords ||= Set.new %w( + AS ASC ASCENDING ASSERT BY CASE COMMIT CONSTRAINT CREATE CSV CYPHER + DELETE DESC DESCENDING DETACH DISTINCT DROP ELSE END ENDS EXPLAIN + FALSE FIELDTERMINATOR FOREACH FROM HEADERS IN INDEX IS JOIN LIMIT + LOAD MATCH MERGE NULL ON OPTIONAL ORDER PERIODIC PROFILE REMOVE + RETURN SCAN SET SKIP START STARTS THEN TRUE UNION UNIQUE UNWIND USING + WHEN WHERE WITH CALL YIELD + ) + end state :root do rule %r/[^\S\n]+/, Text @@ -49,9 +60,9 @@ class Cypher < RegexLexer # - "name (" rule %r/([\w]+)(\s*)(\()/ do |m| name = m[1].upcase - if functions.include? name + if self.class.functions.include? name groups Name::Function, Text::Whitespace, Literal::String::Symbol - elsif keywords.include? name + elsif self.class.keywords.include? name groups Keyword, Text::Whitespace, Literal::String::Symbol else groups Name, Text::Whitespace, Literal::String::Symbol @@ -74,9 +85,9 @@ class Cypher < RegexLexer rule %r/[._\w\d$]+/ do |m| match = m[0].upcase - if pedicates.include? match + if self.class.predicates.include? match token Operator::Word - elsif keywords.include? match + elsif self.class.keywords.include? match token Keyword else token Name From 6ba7b7691b2e76f1ab808570058efe9f162fe254 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:40:17 +0900 Subject: [PATCH 04/15] Use convenience token classes --- lib/rouge/lexers/cypher.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 876718c8a0..9e57617a03 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -47,11 +47,11 @@ def self.keywords rule %r(//.*?$), Comment::Single rule %r([*+\-<>=&|~%^]), Operator - rule %r/[{}),;\[\]]/, Literal::String::Symbol + rule %r/[{}),;\[\]]/, Str::Symbol # literal number rule %r/([_\w\d]+)(:)(\s*)([._\d]+)/ do - groups Name::Label, Literal::String::Delimiter, Text::Whitespace, Literal::Number + groups Name::Label, Str::Delimiter, Text::Whitespace, Num end # function-like @@ -61,11 +61,11 @@ def self.keywords rule %r/([\w]+)(\s*)(\()/ do |m| name = m[1].upcase if self.class.functions.include? name - groups Name::Function, Text::Whitespace, Literal::String::Symbol + groups Name::Function, Text::Whitespace, Str::Symbol elsif self.class.keywords.include? name - groups Keyword, Text::Whitespace, Literal::String::Symbol + groups Keyword, Text::Whitespace, Str::Symbol else - groups Name, Text::Whitespace, Literal::String::Symbol + groups Name, Text::Whitespace, Str::Symbol end end @@ -73,15 +73,15 @@ def self.keywords # number range rule %r/(-?)(\d+)(\.\.)(-?)(\d+)/ do - groups Literal::String::Symbol, Literal::Number, Literal::String::Symbol, Literal::String::Symbol, Literal::Number + groups Str::Symbol, Num, Str::Symbol, Str::Symbol, Num end - rule %r/(\d+)+/, Literal::Number + rule %r/(\d+)+/, Num rule %r([._\w\d]+:), Name::Property # remaining "(" - rule %r/\(/, Literal::String::Symbol + rule %r/\(/, Str::Symbol rule %r/[._\w\d$]+/ do |m| match = m[0].upcase @@ -94,9 +94,9 @@ def self.keywords end end - rule %r/"(\\\\|\\"|[^"])*"/, Str - rule %r/'(\\\\|\\'|[^'])*'/, Str - rule %r/`(\\\\|\\`|[^`])*`/, Str + rule %r/"(\\\\|\\"|[^"])*"/, Str::Double + rule %r/'(\\\\|\\'|[^'])*'/, Str::Single + rule %r/`(\\\\|\\`|[^`])*`/, Str::Backtick rule %r/\n/, Text end From 7af889556e52385ae580aa0fb5047e75cbd5025a Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:42:53 +0900 Subject: [PATCH 05/15] Simplify whitespace rule --- lib/rouge/lexers/cypher.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 9e57617a03..0c5f9eb221 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -43,7 +43,7 @@ def self.keywords end state :root do - rule %r/[^\S\n]+/, Text + rule %r/[\s]+/, Text rule %r(//.*?$), Comment::Single rule %r([*+\-<>=&|~%^]), Operator @@ -97,8 +97,6 @@ def self.keywords rule %r/"(\\\\|\\"|[^"])*"/, Str::Double rule %r/'(\\\\|\\'|[^'])*'/, Str::Single rule %r/`(\\\\|\\`|[^`])*`/, Str::Backtick - - rule %r/\n/, Text end end end From 546e5ad14d42dfccd699dd9f00d930a14e074e96 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:45:02 +0900 Subject: [PATCH 06/15] Change tokens used in number ranges --- lib/rouge/lexers/cypher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 0c5f9eb221..2328cfcf9f 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -72,8 +72,8 @@ def self.keywords rule %r/:[_\w\d]+/, Name::Class # number range - rule %r/(-?)(\d+)(\.\.)(-?)(\d+)/ do - groups Str::Symbol, Num, Str::Symbol, Str::Symbol, Num + rule %r/(-?\d+)(\.\.)(-?\d+)/ do + groups Num, Operator, Num end rule %r/(\d+)+/, Num From c74843e2eb511c23e5ec668b29717f4be5a172e0 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:47:37 +0900 Subject: [PATCH 07/15] Simplify demo --- lib/rouge/demos/cypher | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/rouge/demos/cypher b/lib/rouge/demos/cypher index 94963e9f23..098df7c9ad 100644 --- a/lib/rouge/demos/cypher +++ b/lib/rouge/demos/cypher @@ -1,17 +1,5 @@ // Cypher Mode for Rouge CREATE (john:Person {name: 'John'}) -CREATE (joe:Person {name: 'Joe'}) -CREATE (steve:Person {name: 'Steve'}) -CREATE (sara:Person {name: 'Sara'}) -CREATE (maria:Person {name: 'Maria'}) -CREATE (john)-[:FRIEND]->(joe)-[:FRIEND]->(steve) -CREATE (john)-[:FRIEND]->(sara)-[:FRIEND]->(maria) - MATCH (user)-[:friend]->(follower) WHERE user.name IN ['Joe', 'John', 'Sara', 'Maria', 'Steve'] AND follower.name =~ 'S.*' RETURN user.name, follower.name - -MATCH (n {name: 'John'})-[:FRIEND]-(friend) -WITH n, count(friend) AS friendsCount -WHERE friendsCount > 3 -RETURN n, friendsCount \ No newline at end of file From 3042fd3e1046e3cabe5ee4fe97d21627cf0c1eb3 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 4 Apr 2020 06:50:31 +0900 Subject: [PATCH 08/15] Remove duplicative metacharacters --- lib/rouge/lexers/cypher.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 2328cfcf9f..6dbf36c029 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -50,7 +50,7 @@ def self.keywords rule %r/[{}),;\[\]]/, Str::Symbol # literal number - rule %r/([_\w\d]+)(:)(\s*)([._\d]+)/ do + rule %r/(\w+)(:)(\s*)([._\d]+)/ do groups Name::Label, Str::Delimiter, Text::Whitespace, Num end @@ -58,7 +58,7 @@ def self.keywords # - "name(" # - "name (" # - "name (" - rule %r/([\w]+)(\s*)(\()/ do |m| + rule %r/(\w+)(\s*)(\()/ do |m| name = m[1].upcase if self.class.functions.include? name groups Name::Function, Text::Whitespace, Str::Symbol @@ -69,7 +69,7 @@ def self.keywords end end - rule %r/:[_\w\d]+/, Name::Class + rule %r/:\w+/, Name::Class # number range rule %r/(-?\d+)(\.\.)(-?\d+)/ do @@ -78,12 +78,12 @@ def self.keywords rule %r/(\d+)+/, Num - rule %r([._\w\d]+:), Name::Property + rule %r([.\w]+:), Name::Property # remaining "(" rule %r/\(/, Str::Symbol - rule %r/[._\w\d$]+/ do |m| + rule %r/[.\w$]+/ do |m| match = m[0].upcase if self.class.predicates.include? match token Operator::Word From 244d5dd8b4922b72a5b26af7c5438c9618578888 Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Fri, 10 Apr 2020 09:27:18 +0200 Subject: [PATCH 09/15] Literal number can be negative Co-Authored-By: Michael Camilleri --- lib/rouge/lexers/cypher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 6dbf36c029..26e00634dc 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -50,7 +50,7 @@ def self.keywords rule %r/[{}),;\[\]]/, Str::Symbol # literal number - rule %r/(\w+)(:)(\s*)([._\d]+)/ do + rule %r/(\w+)(:)(\s*)(-?[._\d]+)/ do groups Name::Label, Str::Delimiter, Text::Whitespace, Num end From 519cf8234b711125091701fca8c070a5533eda12 Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Fri, 10 Apr 2020 09:27:34 +0200 Subject: [PATCH 10/15] Number can be negative Co-Authored-By: Michael Camilleri --- lib/rouge/lexers/cypher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 26e00634dc..b0ee9fb26c 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -76,7 +76,7 @@ def self.keywords groups Num, Operator, Num end - rule %r/(\d+)+/, Num + rule %r/-?\d+/, Num rule %r([.\w]+:), Name::Property From 20add3dfe1adfdcf6c1e9550adad66b23a60fad5 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sun, 12 Apr 2020 09:38:49 +0900 Subject: [PATCH 11/15] Add number examples to visual sample --- spec/visual/samples/cypher | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/visual/samples/cypher b/spec/visual/samples/cypher index 3edd0712b7..a439153539 100644 --- a/spec/visual/samples/cypher +++ b/spec/visual/samples/cypher @@ -97,4 +97,6 @@ MATCH (p:Person)-[rel:ACTED_IN]->(m:Movie {title: 'The Matrix'}) RETURN p, rel, m MATCH (p:Person)-[rel]->(:Movie {title:'The Matrix'}) -RETURN p.name, type(rel) \ No newline at end of file +RETURN p.name, type(rel) + +RETURN sign(-17), sign(0.1) From 6b67166678ac7d8c02f27643a0a26df0e8ae3092 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sun, 12 Apr 2020 10:56:53 +0900 Subject: [PATCH 12/15] Add more numeric examples --- spec/visual/samples/cypher | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/visual/samples/cypher b/spec/visual/samples/cypher index a439153539..ae70741ebd 100644 --- a/spec/visual/samples/cypher +++ b/spec/visual/samples/cypher @@ -99,4 +99,4 @@ RETURN p, rel, m MATCH (p:Person)-[rel]->(:Movie {title:'The Matrix'}) RETURN p.name, type(rel) -RETURN sign(-17), sign(0.1) +RETURN sign(-17), sign(0.1), sign(0xABCDEF), sign(000) From f4d3e72705cea64d01e6e5021f05cc07b3ec37c4 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sun, 12 Apr 2020 10:57:23 +0900 Subject: [PATCH 13/15] Add more rules for numbers --- lib/rouge/lexers/cypher.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index b0ee9fb26c..956cb6dca1 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -76,7 +76,12 @@ def self.keywords groups Num, Operator, Num end - rule %r/-?\d+/, Num + # numbers + rule %r/(\d+\.\d*|\d*\.\d+)(e[+-]?\d+)?/i, Num::Float + rule %r/\d+e[+-]?\d+/i, Num::Float + rule %r/0[0-7]+/, Num::Oct + rule %r/0x[a-f0-9]+/i, Num::Hex + rule %r/\d+/, Num::Integer rule %r([.\w]+:), Name::Property From f2bbe3c766d6d2f151319a4f56beda47ac26a380 Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Sun, 12 Apr 2020 12:59:32 +0200 Subject: [PATCH 14/15] Add unicode symbols for left and right arrow and dash --- lib/rouge/lexers/cypher.rb | 15 ++++++++++++++- spec/visual/samples/cypher | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index 956cb6dca1..c31b3924dc 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -42,11 +42,24 @@ def self.keywords ) end + def self.left_arrow_head + @left_arrow_head ||= %w(< \u27e8 \u3008 \ufe64 \uff1c) + end + + def self.right_arrow_head + @right_arrow_head ||= %w(> \u27e9 \u3009 \ufe65 \uff1e) + end + + def self.dash + @dash ||= %w(\- \u00ad \u2010 \u2011 \u2012 \u2013 \u2014 \u2015 \u2212 \ufe58 \ufe63 \uff0d) + end + state :root do rule %r/[\s]+/, Text rule %r(//.*?$), Comment::Single - rule %r([*+\-<>=&|~%^]), Operator + rule %r([*+=&|~%^#{Cypher.right_arrow_head.join('')}#{Cypher.left_arrow_head.join('')}#{Cypher.dash.join('')}]), Operator + rule %r/[{}),;\[\]]/, Str::Symbol # literal number diff --git a/spec/visual/samples/cypher b/spec/visual/samples/cypher index ae70741ebd..3666a5d9f5 100644 --- a/spec/visual/samples/cypher +++ b/spec/visual/samples/cypher @@ -100,3 +100,6 @@ MATCH (p:Person)-[rel]->(:Movie {title:'The Matrix'}) RETURN p.name, type(rel) RETURN sign(-17), sign(0.1), sign(0xABCDEF), sign(000) + +MATCH (p:Person)‒[rel]―〉(:Movie {title:'The Matrix'}) +RETURN p, rel, m \ No newline at end of file From dbf17fa8ab51929b61b41bb9f5e020c0e986e97f Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Tue, 14 Apr 2020 10:38:14 +0200 Subject: [PATCH 15/15] Revert "Add unicode symbols for left and right arrow and dash" This reverts commit f2bbe3c766d6d2f151319a4f56beda47ac26a380. --- lib/rouge/lexers/cypher.rb | 15 +-------------- spec/visual/samples/cypher | 3 --- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/rouge/lexers/cypher.rb b/lib/rouge/lexers/cypher.rb index c31b3924dc..956cb6dca1 100644 --- a/lib/rouge/lexers/cypher.rb +++ b/lib/rouge/lexers/cypher.rb @@ -42,24 +42,11 @@ def self.keywords ) end - def self.left_arrow_head - @left_arrow_head ||= %w(< \u27e8 \u3008 \ufe64 \uff1c) - end - - def self.right_arrow_head - @right_arrow_head ||= %w(> \u27e9 \u3009 \ufe65 \uff1e) - end - - def self.dash - @dash ||= %w(\- \u00ad \u2010 \u2011 \u2012 \u2013 \u2014 \u2015 \u2212 \ufe58 \ufe63 \uff0d) - end - state :root do rule %r/[\s]+/, Text rule %r(//.*?$), Comment::Single - rule %r([*+=&|~%^#{Cypher.right_arrow_head.join('')}#{Cypher.left_arrow_head.join('')}#{Cypher.dash.join('')}]), Operator - + rule %r([*+\-<>=&|~%^]), Operator rule %r/[{}),;\[\]]/, Str::Symbol # literal number diff --git a/spec/visual/samples/cypher b/spec/visual/samples/cypher index 3666a5d9f5..ae70741ebd 100644 --- a/spec/visual/samples/cypher +++ b/spec/visual/samples/cypher @@ -100,6 +100,3 @@ MATCH (p:Person)-[rel]->(:Movie {title:'The Matrix'}) RETURN p.name, type(rel) RETURN sign(-17), sign(0.1), sign(0xABCDEF), sign(000) - -MATCH (p:Person)‒[rel]―〉(:Movie {title:'The Matrix'}) -RETURN p, rel, m \ No newline at end of file