Skip to content

Commit 999292b

Browse files
authored
Merge pull request #183 from eregon/truffleruby-ci
Make the test suite pass on TruffleRuby and add it in CI
2 parents bd9a1c3 + 570a2d1 commit 999292b

File tree

9 files changed

+74
-58
lines changed

9 files changed

+74
-58
lines changed

.github/workflows/main.yml

+2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ jobs:
1212
- '3.0'
1313
- '3.1'
1414
- head
15+
- truffleruby-head
1516
name: CI
1617
runs-on: ubuntu-latest
1718
env:
1819
CI: true
20+
TESTOPTS: --verbose
1921
steps:
2022
- uses: actions/checkout@master
2123
- uses: ruby/setup-ruby@v1

Rakefile

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ require "syntax_tree/rake_tasks"
77
Rake::TestTask.new(:test) do |t|
88
t.libs << "test"
99
t.libs << "lib"
10-
t.test_files = FileList["test/**/*_test.rb"]
10+
test_files = FileList["test/**/*_test.rb"]
11+
if RUBY_ENGINE == "truffleruby"
12+
# language_server.rb uses pattern matching
13+
test_files -= FileList["test/language_server/*_test.rb"]
14+
test_files -= FileList["test/language_server_test.rb"]
15+
end
16+
t.test_files = test_files
1117
end
1218

1319
task default: :test

lib/syntax_tree/cli.rb

+4-3
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,10 @@ def run(item)
192192
# would match the first expression of the input given.
193193
class Expr < Action
194194
def run(item)
195-
case item.handler.parse(item.source)
196-
in Program[statements: Statements[body: [expression]]]
197-
puts expression.construct_keys
195+
program = item.handler.parse(item.source)
196+
if Program === program and expressions = program.statements.body and
197+
expressions.size == 1
198+
puts expressions.first.construct_keys
198199
else
199200
warn("The input to `stree expr` must be a single expression.")
200201
exit(1)

lib/syntax_tree/pattern.rb

+38-32
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ def combine_or(left, right)
8484
end
8585

8686
def compile_node(root)
87-
case root
88-
in AryPtn[constant:, requireds:, rest: nil, posts: []]
87+
if AryPtn === root and root.rest.nil? and root.posts.empty?
88+
constant = root.constant
8989
compiled_constant = compile_node(constant) if constant
9090

91-
preprocessed = requireds.map { |required| compile_node(required) }
91+
preprocessed = root.requireds.map { |required| compile_node(required) }
9292

9393
compiled_requireds = ->(node) do
9494
deconstructed = node.deconstruct
@@ -104,34 +104,37 @@ def compile_node(root)
104104
else
105105
compiled_requireds
106106
end
107-
in Binary[left:, operator: :|, right:]
108-
combine_or(compile_node(left), compile_node(right))
109-
in Const[value:] if SyntaxTree.const_defined?(value)
110-
clazz = SyntaxTree.const_get(value)
107+
elsif Binary === root and root.operator == :|
108+
combine_or(compile_node(root.left), compile_node(root.right))
109+
elsif Const === root and SyntaxTree.const_defined?(root.value)
110+
clazz = SyntaxTree.const_get(root.value)
111111

112112
->(node) { node.is_a?(clazz) }
113-
in Const[value:] if Object.const_defined?(value)
114-
clazz = Object.const_get(value)
113+
elsif Const === root and Object.const_defined?(root.value)
114+
clazz = Object.const_get(root.value)
115115

116116
->(node) { node.is_a?(clazz) }
117-
in ConstPathRef[
118-
parent: VarRef[value: Const[value: "SyntaxTree"]], constant:
119-
]
120-
compile_node(constant)
121-
in DynaSymbol[parts: []]
117+
elsif ConstPathRef === root and VarRef === root.parent and
118+
Const === root.parent.value and
119+
root.parent.value.value == "SyntaxTree"
120+
compile_node(root.constant)
121+
elsif DynaSymbol === root and root.parts.empty?
122122
symbol = :""
123123

124124
->(node) { node == symbol }
125-
in DynaSymbol[parts: [TStringContent[value:]]]
126-
symbol = value.to_sym
125+
elsif DynaSymbol === root and parts = root.parts and parts.size == 1 and
126+
TStringContent === parts[0]
127+
symbol = parts[0].value.to_sym
127128

128-
->(attribute) { attribute == value }
129-
in HshPtn[constant:, keywords:, keyword_rest: nil]
130-
compiled_constant = compile_node(constant)
129+
->(node) { node == symbol }
130+
elsif HshPtn === root and root.keyword_rest.nil?
131+
compiled_constant = compile_node(root.constant)
131132

132133
preprocessed =
133-
keywords.to_h do |keyword, value|
134-
raise NoMatchingPatternError unless keyword.is_a?(Label)
134+
root.keywords.to_h do |keyword, value|
135+
unless keyword.is_a?(Label)
136+
raise CompilationError, PP.pp(root, +"").chomp
137+
end
135138
[keyword.value.chomp(":").to_sym, compile_node(value)]
136139
end
137140

@@ -148,25 +151,28 @@ def compile_node(root)
148151
else
149152
compiled_keywords
150153
end
151-
in RegexpLiteral[parts: [TStringContent[value:]]]
152-
regexp = /#{value}/
154+
elsif RegexpLiteral === root and parts = root.parts and
155+
parts.size == 1 and TStringContent === parts[0]
156+
regexp = /#{parts[0].value}/
153157

154158
->(attribute) { regexp.match?(attribute) }
155-
in StringLiteral[parts: []]
159+
elsif StringLiteral === root and root.parts.empty?
156160
->(attribute) { attribute == "" }
157-
in StringLiteral[parts: [TStringContent[value:]]]
161+
elsif StringLiteral === root and parts = root.parts and
162+
parts.size == 1 and TStringContent === parts[0]
163+
value = parts[0].value
158164
->(attribute) { attribute == value }
159-
in SymbolLiteral[value:]
160-
symbol = value.value.to_sym
165+
elsif SymbolLiteral === root
166+
symbol = root.value.value.to_sym
161167

162168
->(attribute) { attribute == symbol }
163-
in VarRef[value: Const => value]
164-
compile_node(value)
165-
in VarRef[value: Kw[value: "nil"]]
169+
elsif VarRef === root and Const === root.value
170+
compile_node(root.value)
171+
elsif VarRef === root and Kw === root.value and root.value.value.nil?
166172
->(attribute) { attribute.nil? }
173+
else
174+
raise CompilationError, PP.pp(root, +"").chomp
167175
end
168-
rescue NoMatchingPatternError
169-
raise CompilationError, PP.pp(root, +"").chomp
170176
end
171177
end
172178
end

test/cli_test.rb

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def test_inline_script
148148
end
149149

150150
def test_multiple_inline_scripts
151+
skip if RUBY_ENGINE == "truffleruby" # Relies on a thread-safe StringIO
151152
stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1 -e 2+2]) }
152153
assert_equal(["1 + 1", "2 + 2"], stdio.split("\n").sort)
153154
end
@@ -172,6 +173,7 @@ def test_plugins
172173
def test_language_server
173174
prev_stdin = $stdin
174175
prev_stdout = $stdout
176+
skip unless SUPPORTS_PATTERN_MATCHING
175177

176178
request = { method: "shutdown" }.merge(jsonrpc: "2.0").to_json
177179
$stdin =

test/idempotency_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
return unless ENV["CI"]
3+
return unless ENV["CI"] and RUBY_ENGINE != "truffleruby"
44
require_relative "test_helper"
55

66
module SyntaxTree

test/location_test.rb

+4-8
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,15 @@ def test_lines
1414
def test_deconstruct
1515
location = Location.fixed(line: 1, char: 0, column: 0)
1616

17-
case location
18-
in [start_line, 0, 0, *]
19-
assert_equal(1, start_line)
20-
end
17+
assert_equal(1, location.start_line)
18+
assert_equal(0, location.start_char)
19+
assert_equal(0, location.start_column)
2120
end
2221

2322
def test_deconstruct_keys
2423
location = Location.fixed(line: 1, char: 0, column: 0)
2524

26-
case location
27-
in start_line:
28-
assert_equal(1, start_line)
29-
end
25+
assert_equal(1, location.start_line)
3026
end
3127
end
3228
end

test/node_test.rb

+3-4
Original file line numberDiff line numberDiff line change
@@ -759,10 +759,9 @@ def test_program
759759
program = parser.parse
760760
refute(parser.error?)
761761

762-
case program
763-
in statements: { body: [statement] }
764-
assert_kind_of(VCall, statement)
765-
end
762+
statements = program.statements.body
763+
assert_equal 1, statements.size
764+
assert_kind_of(VCall, statements.first)
766765

767766
json = JSON.parse(program.to_json)
768767
io = StringIO.new

test/test_helper.rb

+13-9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
require "pp"
1818
require "minitest/autorun"
1919

20+
SUPPORTS_PATTERN_MATCHING = RUBY_ENGINE != "truffleruby"
21+
2022
module SyntaxTree
2123
module Assertions
2224
class Recorder
@@ -67,15 +69,17 @@ def assert_syntax_tree(node)
6769
refute_includes(json, "#<")
6870
assert_equal(type, JSON.parse(json)["type"])
6971

70-
# Get a match expression from the node, then assert that it can in fact
71-
# match the node.
72-
# rubocop:disable all
73-
assert(eval(<<~RUBY))
74-
case node
75-
in #{node.construct_keys}
76-
true
77-
end
78-
RUBY
72+
if SUPPORTS_PATTERN_MATCHING
73+
# Get a match expression from the node, then assert that it can in fact
74+
# match the node.
75+
# rubocop:disable all
76+
assert(eval(<<~RUBY))
77+
case node
78+
in #{node.construct_keys}
79+
true
80+
end
81+
RUBY
82+
end
7983
end
8084

8185
Minitest::Test.include(self)

0 commit comments

Comments
 (0)