rcas 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CITATION.cff +17 -0
- data/DESIGN.md +783 -0
- data/LICENSE +21 -0
- data/MANUAL.md +6265 -0
- data/README.md +267 -0
- data/bin/rcas +9 -0
- data/bin/rcas-app +9 -0
- data/bin/rcas-chat +9 -0
- data/lib/rcas/algebraic.rb +481 -0
- data/lib/rcas/analysis.rb +966 -0
- data/lib/rcas/app/launcher.rb +203 -0
- data/lib/rcas/app/public/app.css +402 -0
- data/lib/rcas/app/public/app.js +449 -0
- data/lib/rcas/app/public/index.html +46 -0
- data/lib/rcas/app/server.rb +220 -0
- data/lib/rcas/app/window.rb +94 -0
- data/lib/rcas/app/worksheet.rb +290 -0
- data/lib/rcas/app.rb +168 -0
- data/lib/rcas/background.rb +758 -0
- data/lib/rcas/chat/assistant.rb +199 -0
- data/lib/rcas/chat/picker.rb +164 -0
- data/lib/rcas/chat/repl.rb +583 -0
- data/lib/rcas/chat/session.rb +137 -0
- data/lib/rcas/chat/settings.rb +71 -0
- data/lib/rcas/chat/style.rb +30 -0
- data/lib/rcas/chat/tool.rb +53 -0
- data/lib/rcas/chat/ui.rb +316 -0
- data/lib/rcas/chat/usage.rb +62 -0
- data/lib/rcas/chat/workspace.rb +132 -0
- data/lib/rcas/chat.rb +54 -0
- data/lib/rcas/coefficients.rb +170 -0
- data/lib/rcas/combinatorics.rb +274 -0
- data/lib/rcas/complex_parts.rb +160 -0
- data/lib/rcas/constants.rb +129 -0
- data/lib/rcas/core_ext.rb +35 -0
- data/lib/rcas/decide.rb +501 -0
- data/lib/rcas/decompositions.rb +241 -0
- data/lib/rcas/differentiate.rb +144 -0
- data/lib/rcas/discussion.rb +558 -0
- data/lib/rcas/distributions.rb +980 -0
- data/lib/rcas/dixon.rb +95 -0
- data/lib/rcas/docs.rb +321 -0
- data/lib/rcas/domains.rb +728 -0
- data/lib/rcas/expand.rb +174 -0
- data/lib/rcas/expression.rb +613 -0
- data/lib/rcas/factor.rb +605 -0
- data/lib/rcas/finite_field.rb +577 -0
- data/lib/rcas/fourier.rb +118 -0
- data/lib/rcas/fps.rb +678 -0
- data/lib/rcas/fraction.rb +126 -0
- data/lib/rcas/functions.rb +1136 -0
- data/lib/rcas/gcd.rb +112 -0
- data/lib/rcas/geometry.rb +266 -0
- data/lib/rcas/groebner.rb +162 -0
- data/lib/rcas/hold.rb +277 -0
- data/lib/rcas/hypothesis.rb +364 -0
- data/lib/rcas/inequalities.rb +689 -0
- data/lib/rcas/integral_functions.rb +260 -0
- data/lib/rcas/integrate.rb +1589 -0
- data/lib/rcas/integrate_substitutions.rb +434 -0
- data/lib/rcas/interpolate.rb +40 -0
- data/lib/rcas/irb.rb +146 -0
- data/lib/rcas/laplace.rb +159 -0
- data/lib/rcas/latex.rb +556 -0
- data/lib/rcas/lattice.rb +172 -0
- data/lib/rcas/linear_algebra.rb +117 -0
- data/lib/rcas/linear_program.rb +416 -0
- data/lib/rcas/lint.rb +79 -0
- data/lib/rcas/matrix.rb +531 -0
- data/lib/rcas/matrix_multiply.rb +202 -0
- data/lib/rcas/multimodular.rb +286 -0
- data/lib/rcas/named_polynomials.rb +274 -0
- data/lib/rcas/number_theory.rb +443 -0
- data/lib/rcas/numerics.rb +825 -0
- data/lib/rcas/ode.rb +488 -0
- data/lib/rcas/openmath/objects.rb +364 -0
- data/lib/rcas/openmath/phrasebook.rb +551 -0
- data/lib/rcas/openmath/popcorn.rb +518 -0
- data/lib/rcas/openmath/xml.rb +309 -0
- data/lib/rcas/openmath.rb +49 -0
- data/lib/rcas/petkovsek.rb +165 -0
- data/lib/rcas/piecewise.rb +488 -0
- data/lib/rcas/plot.rb +763 -0
- data/lib/rcas/plot3d.rb +419 -0
- data/lib/rcas/poly_matrix.rb +318 -0
- data/lib/rcas/poly_recurrence.rb +117 -0
- data/lib/rcas/polynomial.rb +466 -0
- data/lib/rcas/precision.rb +925 -0
- data/lib/rcas/printer.rb +150 -0
- data/lib/rcas/product.rb +155 -0
- data/lib/rcas/q_difference.rb +296 -0
- data/lib/rcas/q_functions.rb +158 -0
- data/lib/rcas/q_summation.rb +308 -0
- data/lib/rcas/q_zeilberger.rb +199 -0
- data/lib/rcas/random.rb +506 -0
- data/lib/rcas/rational_function.rb +186 -0
- data/lib/rcas/recurrence.rb +323 -0
- data/lib/rcas/render.rb +431 -0
- data/lib/rcas/results.rb +192 -0
- data/lib/rcas/scalar.rb +219 -0
- data/lib/rcas/series.rb +726 -0
- data/lib/rcas/simplify.rb +649 -0
- data/lib/rcas/solve.rb +2002 -0
- data/lib/rcas/special.rb +163 -0
- data/lib/rcas/statistics.rb +175 -0
- data/lib/rcas/steps.rb +835 -0
- data/lib/rcas/summation.rb +532 -0
- data/lib/rcas/trig.rb +264 -0
- data/lib/rcas/van_hoeij.rb +241 -0
- data/lib/rcas/vector.rb +175 -0
- data/lib/rcas/vector_calculus.rb +411 -0
- data/lib/rcas/version.rb +5 -0
- data/lib/rcas/zeilberger.rb +358 -0
- data/lib/rcas.rb +91 -0
- data/package.json +8 -0
- metadata +206 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RCAS
|
|
4
|
+
# OpenMath [OM19]: the abstract objects of the standard.
|
|
5
|
+
#
|
|
6
|
+
# An OpenMath object is not XML. XML is one of its encodings - the binary
|
|
7
|
+
# encoding and strict content MathML are others - so the classes below are
|
|
8
|
+
# the thing itself, and OpenMath::XML is one way of writing it down:
|
|
9
|
+
#
|
|
10
|
+
# om = RCAS.openmath(:x**2 + 1) # => arith1.plus(arith1.power(x, 2), 1)
|
|
11
|
+
# om.to_xml # => "<OMOBJ ...>...</OMOBJ>"
|
|
12
|
+
# RCAS.from_openmath(om.to_xml) # => x**2 + 1, unevaluated
|
|
13
|
+
#
|
|
14
|
+
# A class for each kind of object the standard defines: the six basic ones
|
|
15
|
+
# (Int, Double, Text, Bytes, ContentSymbol, Variable), the four compound
|
|
16
|
+
# ones (Application, Bind, Attribution, Error), the derived one (Foreign),
|
|
17
|
+
# and Reference, BVar, AttrPair and the wrapper Root, which the encodings
|
|
18
|
+
# need. Six of the standard's own words would shadow something inside this
|
|
19
|
+
# module - Integer, Float, String and Object are Ruby's, Binding is Ruby's
|
|
20
|
+
# too, and Symbol already means the indeterminate :x in rcas - so those are
|
|
21
|
+
# Int, Double, Text, Root, Bind and ContentSymbol.
|
|
22
|
+
#
|
|
23
|
+
# Note that OpenMath::Error is a *node*, not an exception: OME is the
|
|
24
|
+
# object you get back for a symbol the sender could not evaluate. The
|
|
25
|
+
# exceptions here are ParseError and EncodeError.
|
|
26
|
+
#
|
|
27
|
+
# Sources: the OpenMath 2.0 standard [OM19, ch. 2] for the objects, [OM19,
|
|
28
|
+
# ch. 4] for the XML encoding, the official content dictionaries for the
|
|
29
|
+
# phrasebook.
|
|
30
|
+
module OpenMath
|
|
31
|
+
# Where the official content dictionaries live, and a private CD of our
|
|
32
|
+
# own for the names rcas has and OpenMath has not (gamma, zeta, erf, the
|
|
33
|
+
# integral functions, RootOf). A cdbase is an identifier, not a URL that
|
|
34
|
+
# has to resolve.
|
|
35
|
+
CDBASE = "http://www.openmath.org/cd"
|
|
36
|
+
RCAS_CDBASE = "https://github.com/no-dashes/rcas/cd"
|
|
37
|
+
RCAS_CD = "rcas1"
|
|
38
|
+
|
|
39
|
+
OBJECT_VERSION = "2.0"
|
|
40
|
+
|
|
41
|
+
class ParseError < StandardError; end
|
|
42
|
+
class EncodeError < StandardError; end
|
|
43
|
+
|
|
44
|
+
# Common behaviour: frozen, structurally compared, walkable.
|
|
45
|
+
class Node
|
|
46
|
+
# An optional xml:id, carried so structure sharing survives a round
|
|
47
|
+
# trip. Never part of equality: two objects are equal when they say
|
|
48
|
+
# the same thing, whatever they are called.
|
|
49
|
+
attr_reader :id
|
|
50
|
+
|
|
51
|
+
def children = []
|
|
52
|
+
def leaf? = children.empty?
|
|
53
|
+
|
|
54
|
+
def each_node(&block)
|
|
55
|
+
return enum_for(:each_node) unless block
|
|
56
|
+
stack = [self]
|
|
57
|
+
until stack.empty?
|
|
58
|
+
node = stack.pop
|
|
59
|
+
yield node
|
|
60
|
+
stack.concat(node.children.reverse)
|
|
61
|
+
end
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# A copy carrying an xml:id (the nodes themselves are frozen).
|
|
66
|
+
def identified(id)
|
|
67
|
+
copy = dup
|
|
68
|
+
copy.instance_variable_set(:@id, id&.to_s&.freeze)
|
|
69
|
+
copy.freeze
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def ==(other) = other.class == self.class && other.state == state
|
|
73
|
+
alias eql? ==
|
|
74
|
+
def hash = [self.class, *state].hash
|
|
75
|
+
|
|
76
|
+
# An OpenMath object proper. Foreign content is a *derived* object in
|
|
77
|
+
# the standard's words, "not an OpenMath object", and may stand only
|
|
78
|
+
# as the value of an attribution or an argument of an error.
|
|
79
|
+
def object? = true
|
|
80
|
+
|
|
81
|
+
def to_xml(**opts) = XML.encode(self, **opts)
|
|
82
|
+
|
|
83
|
+
# The sugared notation a person would type; #to_s is the same notation
|
|
84
|
+
# with every symbol written out as cd.name.
|
|
85
|
+
def to_popcorn = Popcorn.render(self)
|
|
86
|
+
def to_s = Popcorn.render(self, sugar: false)
|
|
87
|
+
|
|
88
|
+
# The rcas object this stands for (see Phrasebook).
|
|
89
|
+
def to_expression = Phrasebook.to_expression(self)
|
|
90
|
+
|
|
91
|
+
def inspect = to_s
|
|
92
|
+
|
|
93
|
+
protected
|
|
94
|
+
|
|
95
|
+
# What equality and #hash look at; the children unless said otherwise.
|
|
96
|
+
def state = children
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# OMI, OMF, OMSTR, OMB: an object that is just its value.
|
|
100
|
+
class Value < Node
|
|
101
|
+
attr_reader :value
|
|
102
|
+
|
|
103
|
+
def initialize(value)
|
|
104
|
+
@value = convert(value)
|
|
105
|
+
freeze
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
|
|
110
|
+
def state = [value]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# OMI: an integer of any size.
|
|
114
|
+
class Int < Value
|
|
115
|
+
private def convert(v) = Integer(v)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# OMF: an IEEE 754 double.
|
|
119
|
+
class Double < Value
|
|
120
|
+
private def convert(v) = Float(v)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# OMSTR: a string of Unicode characters.
|
|
124
|
+
class Text < Value
|
|
125
|
+
private def convert(v) = v.to_s.dup.freeze
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# OMB: a byte array.
|
|
129
|
+
class Bytes < Value
|
|
130
|
+
private def convert(v) = v.to_s.b.freeze
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# OMV: a variable. rcas calls this an indeterminate.
|
|
134
|
+
class Variable < Node
|
|
135
|
+
attr_reader :name
|
|
136
|
+
|
|
137
|
+
def initialize(name)
|
|
138
|
+
@name = name.to_s.dup.freeze
|
|
139
|
+
freeze
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
protected
|
|
143
|
+
|
|
144
|
+
def state = [name]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# OMS: a symbol, i.e. the name of a mathematical object in a content
|
|
148
|
+
# dictionary. arith1.plus is the addition of the CD arith1, whatever the
|
|
149
|
+
# sender happens to call it.
|
|
150
|
+
class ContentSymbol < Node
|
|
151
|
+
attr_reader :cd, :name, :cdbase
|
|
152
|
+
|
|
153
|
+
def initialize(cd, name, cdbase: nil)
|
|
154
|
+
@cd = cd.to_s.dup.freeze
|
|
155
|
+
@name = name.to_s.dup.freeze
|
|
156
|
+
@cdbase = cdbase&.to_s&.dup&.freeze
|
|
157
|
+
freeze
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def key = [cd, name]
|
|
161
|
+
def official? = cdbase.nil? || cdbase == CDBASE
|
|
162
|
+
|
|
163
|
+
protected
|
|
164
|
+
|
|
165
|
+
def state = [cd, name, cdbase]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# OMA: an application, head first.
|
|
169
|
+
class Application < Node
|
|
170
|
+
attr_reader :head, :args
|
|
171
|
+
|
|
172
|
+
def initialize(head, *args)
|
|
173
|
+
args = args.first if args.size == 1 && args.first.is_a?(Array)
|
|
174
|
+
@head = OpenMath.object!(head, "the head of an application")
|
|
175
|
+
@args = args.map { |a| OpenMath.object!(a, "an argument of an application") }.freeze
|
|
176
|
+
freeze
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def children = [head, *args]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# OMBVAR: the bound variables of a binding.
|
|
183
|
+
class BVar < Node
|
|
184
|
+
attr_reader :vars
|
|
185
|
+
|
|
186
|
+
def initialize(*vars)
|
|
187
|
+
vars = vars.first if vars.size == 1 && vars.first.is_a?(Array)
|
|
188
|
+
@vars = vars.map { |v| v.is_a?(Node) ? v : Variable.new(v) }.freeze
|
|
189
|
+
freeze
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def children = vars
|
|
193
|
+
def to_s = vars.join(", ")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# OMBIND: a binding - fns1.lambda[x -> x^2] and everything built on it.
|
|
197
|
+
class Bind < Node
|
|
198
|
+
attr_reader :binder, :bvar, :body
|
|
199
|
+
|
|
200
|
+
def initialize(binder, bvar, body)
|
|
201
|
+
@binder = OpenMath.object!(binder, "the binder of a binding")
|
|
202
|
+
@bvar = bvar.is_a?(BVar) ? bvar : BVar.new(bvar)
|
|
203
|
+
@body = OpenMath.object!(body, "the body of a binding")
|
|
204
|
+
freeze
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def vars = bvar.vars
|
|
208
|
+
def children = [binder, bvar, body]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# One key/value pair of an attribution.
|
|
212
|
+
class AttrPair < Node
|
|
213
|
+
attr_reader :key, :value
|
|
214
|
+
|
|
215
|
+
def initialize(key, value)
|
|
216
|
+
@key = OpenMath.object!(key, "the key of an attribution")
|
|
217
|
+
@value = OpenMath.lift(value) # a value may be foreign
|
|
218
|
+
freeze
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def children = [key, value]
|
|
222
|
+
def to_s = "#{key} -> #{value}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# OMATTR: an object with attributes attached.
|
|
226
|
+
class Attribution < Node
|
|
227
|
+
attr_reader :pairs, :object
|
|
228
|
+
|
|
229
|
+
def initialize(pairs, object)
|
|
230
|
+
@pairs = pairs.map { |p| p.is_a?(AttrPair) ? p : AttrPair.new(*p) }.freeze
|
|
231
|
+
@object = OpenMath.lift(object)
|
|
232
|
+
freeze
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def children = [*pairs, object]
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# OME: an error object. Data, not an exception - it is what a sender
|
|
239
|
+
# hands back for a symbol it could not deal with.
|
|
240
|
+
class Error < Node
|
|
241
|
+
attr_reader :symbol, :args
|
|
242
|
+
|
|
243
|
+
def initialize(symbol, *args)
|
|
244
|
+
args = args.first if args.size == 1 && args.first.is_a?(Array)
|
|
245
|
+
@symbol = OpenMath.object!(symbol, "the symbol of an error")
|
|
246
|
+
@args = args.map { |a| OpenMath.lift(a) }.freeze # an argument may be foreign
|
|
247
|
+
freeze
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def children = [symbol, *args]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# OMR: a reference to another object, by which a tree becomes a DAG.
|
|
254
|
+
class Reference < Node
|
|
255
|
+
attr_reader :href
|
|
256
|
+
|
|
257
|
+
def initialize(href)
|
|
258
|
+
@href = href.to_s.dup.freeze
|
|
259
|
+
freeze
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
protected
|
|
263
|
+
|
|
264
|
+
def state = [href]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# OMFOREIGN: data that is not OpenMath - a presentation-MathML or LaTeX
|
|
268
|
+
# rendering of the object it is attached to, an image, a comment. The
|
|
269
|
+
# content is carried exactly as it came, markup and all, and never
|
|
270
|
+
# interpreted. A derived object: legal as the value of an attribution
|
|
271
|
+
# or an argument of an error, nowhere else.
|
|
272
|
+
class Foreign < Node
|
|
273
|
+
attr_reader :content, :encoding
|
|
274
|
+
|
|
275
|
+
def initialize(content, encoding: nil)
|
|
276
|
+
@content = content.to_s.dup.freeze
|
|
277
|
+
@encoding = encoding&.to_s&.dup&.freeze
|
|
278
|
+
freeze
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def object? = false
|
|
282
|
+
|
|
283
|
+
protected
|
|
284
|
+
|
|
285
|
+
def state = [content, encoding]
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# OMOBJ: the wrapper that says "what follows is an OpenMath object".
|
|
289
|
+
# It carries the version and nothing mathematical, so it prints as its
|
|
290
|
+
# own contents.
|
|
291
|
+
class Root < Node
|
|
292
|
+
attr_reader :object, :version
|
|
293
|
+
|
|
294
|
+
def initialize(object, version: OBJECT_VERSION)
|
|
295
|
+
@object = OpenMath.object!(object, "the content of an OpenMath object")
|
|
296
|
+
@version = version.to_s.dup.freeze
|
|
297
|
+
freeze
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def children = [object]
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
module_function
|
|
304
|
+
|
|
305
|
+
# Ruby values as OpenMath objects: 3, 2.5, "text", :x. Anything more
|
|
306
|
+
# mathematical than that goes through the Phrasebook.
|
|
307
|
+
def lift(obj)
|
|
308
|
+
case obj
|
|
309
|
+
when Node then obj
|
|
310
|
+
when Integer then Int.new(obj)
|
|
311
|
+
when Float then Double.new(obj)
|
|
312
|
+
when String then Text.new(obj)
|
|
313
|
+
when Symbol then Variable.new(obj)
|
|
314
|
+
else raise TypeError, "can't turn #{obj.class} into an OpenMath object"
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# An OpenMath object where one is required; foreign content is not one.
|
|
319
|
+
def object!(obj, where)
|
|
320
|
+
node = lift(obj)
|
|
321
|
+
raise TypeError, "foreign content may not be #{where}" unless node.object?
|
|
322
|
+
node
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# The symbol +name+ of the content dictionary +cd+: sym("arith1", "plus")
|
|
326
|
+
def sym(cd, name, cdbase: nil) = ContentSymbol.new(cd, name, cdbase: cdbase)
|
|
327
|
+
|
|
328
|
+
# A symbol of rcas's own content dictionary, for what OpenMath has no
|
|
329
|
+
# official name for.
|
|
330
|
+
def rcas_sym(name) = ContentSymbol.new(RCAS_CD, name, cdbase: RCAS_CDBASE)
|
|
331
|
+
|
|
332
|
+
# Replace every OMR by the object it points at, so the result is a tree.
|
|
333
|
+
# Unknown targets are left alone.
|
|
334
|
+
def dereference(node, table = nil)
|
|
335
|
+
table ||= node.each_node.filter_map { |n| [n.id, n] if n.id }.to_h
|
|
336
|
+
return node if table.empty?
|
|
337
|
+
expand(node, table, 0)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def expand(node, table, depth)
|
|
341
|
+
raise ParseError, "cyclic references" if depth > 64
|
|
342
|
+
if node.is_a?(Reference)
|
|
343
|
+
target = table[node.href.sub(/\A#/, "")]
|
|
344
|
+
return node unless target
|
|
345
|
+
return expand(target, table, depth + 1)
|
|
346
|
+
end
|
|
347
|
+
children = node.children.map { |c| expand(c, table, depth + 1) }
|
|
348
|
+
children == node.children ? node : rebuild(node, children)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def rebuild(node, children)
|
|
352
|
+
case node
|
|
353
|
+
when Root then Root.new(children.first, version: node.version)
|
|
354
|
+
when Application then Application.new(children.first, children[1..])
|
|
355
|
+
when BVar then BVar.new(children)
|
|
356
|
+
when Bind then Bind.new(children[0], children[1], children[2])
|
|
357
|
+
when AttrPair then AttrPair.new(children[0], children[1])
|
|
358
|
+
when Attribution then Attribution.new(children[0..-2], children.last)
|
|
359
|
+
when Error then Error.new(children.first, children[1..])
|
|
360
|
+
else node
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|