-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparslet_toml.rb
More file actions
191 lines (161 loc) · 4.81 KB
/
parslet_toml.rb
File metadata and controls
191 lines (161 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env ruby
# frozen_string_literal: true
# Example: Using TreeHaver with TOML Parslet Grammar
#
# This demonstrates how tree_haver's Parslet backend provides a pure Ruby
# fallback for TOML parsing using the toml gem when tree-sitter-toml is unavailable.
#
# toml gem: https://github.com/jm/toml
# TOML spec: https://toml.io/
require "bundler/inline"
gemfile do
source "https://gem.coop"
# Load tree_haver from local path
gem "tree_haver", path: File.expand_path("..", __dir__)
# TOML parser with Parslet grammar
gem "toml", path: File.expand_path("../../toml", __dir__)
gem "parslet"
end
require "tree_haver"
require "toml"
puts "=" * 70
puts "TreeHaver + TOML (Parslet Grammar) Example"
puts "=" * 70
puts
# Example TOML configuration
toml_source = <<~TOML
# Application configuration
[database]
host = "localhost"
port = 5432
username = "admin"
[server]
bind = "0.0.0.0"
port = 8080
workers = 4
[[services]]
name = "api"
enabled = true
[[services]]
name = "worker"
enabled = false
TOML
puts "TOML Source:"
puts "-" * 70
puts toml_source
puts
# Register TOML's Parslet grammar with TreeHaver
puts "Registering TOML grammar with TreeHaver..."
TreeHaver.register_language(
:toml,
grammar_class: TOML::Parslet,
gem_name: "toml",
)
puts "✓ Registered"
puts
# Force Parslet backend (pure Ruby parsing)
puts "Setting backend to Parslet (pure Ruby)..."
TreeHaver.backend = :parslet
puts "✓ Backend: #{TreeHaver.backend_module}"
puts "✓ This is 100% pure Ruby - no native extensions!"
puts
# Parse the TOML source
puts "Parsing TOML source with TreeHaver..."
parser = TreeHaver::Parser.new
parser.language = TreeHaver::Language.toml
tree = parser.parse(toml_source)
puts "✓ Parsed successfully"
puts
# Explore the AST
root = tree.root_node
puts "Root Node:"
puts " Type: #{root.type}"
puts " Structural?: #{root.structural?}"
puts " Children: #{root.child_count}"
puts
# NOTE: toml gem is strict, and will not work with overly simple TOML like this:
# toml_source = 'key = "value"'
# tree = parser.parse(toml_source)
# puts "✓ Parsed successfully"
# # Explore the AST
# root = tree.root_node
# puts "Root Node:"
# puts " Type: #{root.type}"
# puts " Structural?: #{root.structural?}"
# puts " Children: #{root.child_count}"
# puts
# # thing = TOML.load(toml_source)
# # puts thing.inspect
# Helper to display node tree
def show_tree(node, indent = 0, max_depth = 3)
return if indent > max_depth
prefix = " " * indent
marker = node.structural? ? "📦" : "🔤"
# Show node info
text_preview = node.text[0..40].gsub("\n", "\\n")
puts "#{prefix}#{marker} #{node.type}: #{text_preview.inspect}"
# Recurse into children (limit to avoid too much output)
if node.child_count > 0 && node.child_count < 15
node.children.each { |child| show_tree(child, indent + 1, max_depth) }
elsif node.child_count > 0
puts "#{prefix} ... #{node.child_count} children ..."
end
end
puts "AST Structure (first 3 levels):"
puts "-" * 70
show_tree(root)
puts
# Row number validation
puts "=== Row Number Validation ==="
row_errors = []
puts "Checking structural nodes for position info:"
i = 0
root.each do |child|
next unless child.structural?
if child.respond_to?(:start_point)
start_row = child.start_point.row
end_row = child.end_point.row
puts " Node #{i}: #{child.type} - rows #{start_row}-#{end_row}"
# For multiline TOML, tables should have different start rows
if child.type.to_s == "table" && child.to_s.include?("[server]")
if start_row == 0
row_errors << "[server] table has start_row=0, expected row > 0"
end
end
else
puts " Node #{i}: #{child.type} - position info not available (Parslet nodes)"
end
i += 1
end
puts
if row_errors.empty?
puts "✓ Row numbers look correct (or not applicable for Parslet backend)"
else
puts "✗ Row number issues detected:"
row_errors.each { |err| puts " - #{err}" }
exit 1
end
puts
# Demonstrate the advantages
puts "=" * 70
puts "Why Use Parslet Backend?"
puts "=" * 70
puts "1. 100% pure Ruby - no native extensions needed"
puts "2. Works on all Ruby implementations (MRI, JRuby, TruffleRuby)"
puts "3. No compilation step required"
puts "4. Perfect for environments without native build tools"
puts "5. Uses the well-established toml gem (Parslet-based)"
puts
puts "Note: Parslet parsing is slower than native tree-sitter,"
puts "but provides maximum portability."
puts
puts "Parslet vs Citrus:"
puts " - Parslet: Grammar is a class (TOML::Parslet), instantiate then parse"
puts " - Citrus: Grammar is a module (TomlRB::Document), call parse directly"
puts
puts "Use Cases:"
puts " - Cloud functions with restricted native dependencies"
puts " - Embedded Ruby environments"
puts " - Quick prototyping without compilation"
puts " - Cross-platform CI/CD without native toolchains"
puts "=" * 70