Module: Fusion::Interpreter::Builtins
Instance Method Summary collapse
-
#add(v) ⇒ Object
— arithmetic —.
-
#and_(v) ⇒ Object
‘and`/`or`/`not` judge truthiness (Ruby-style: `false` and `null` are falsey, everything else truthy), not strict booleans, and always return a boolean.
- #chars(v) ⇒ Object
- #concat(v) ⇒ Object
- #divide(v) ⇒ Object
-
#equals(v) ⇒ Object
— comparison —.
- #floor(v) ⇒ Object
-
#get(v) ⇒ Object
Read from an array (integer index, negative counts from the end) or an object (string key) — mirroring the ‘[]` operator (reference §8).
- #install(table, interp) ⇒ Object
- #join(v) ⇒ Object
-
#keys(v) ⇒ Object
— object key enumeration (Tier 0: patterns can’t enumerate unknown keys) —.
-
#length(v) ⇒ Object
— strings and structure bridges —.
- #less_than(v) ⇒ Object
- #mod(v) ⇒ Object
- #multiply(v) ⇒ Object
- #negate(v) ⇒ Object
- #not_(v) ⇒ Object
- #or_(v) ⇒ Object
- #parse_number(v) ⇒ Object
-
#set(v) ⇒ Object
Return a new array/object with one entry set.
- #subtract(v) ⇒ Object
- #to_object(v) ⇒ Object
- #to_string(v) ⇒ Object
- #values(v) ⇒ Object
Instance Method Details
#add(v) ⇒ Object
— arithmetic —
54 55 56 57 58 59 60 61 |
# File 'lib/fusion/interpreter/builtins.rb', line 54 def add(v) return v if v.is_a?(ErrorVal) return error("argument_error", "add", v, "expected [_, _]") unless pair?(v) return error("type_error", "add", v, "expected numbers") unless numeric?(v[0]) return error("type_error", "add", v, "expected numbers") unless numeric?(v[1]) v[0] + v[1] end |
#and_(v) ⇒ Object
‘and`/`or`/`not` judge truthiness (Ruby-style: `false` and `null` are falsey, everything else truthy), not strict booleans, and always return a boolean. They share the interpreter’s ‘truthy?`, the same test `?` guards use.
149 150 151 152 153 154 |
# File 'lib/fusion/interpreter/builtins.rb', line 149 def and_(v) return v if v.is_a?(ErrorVal) return error("argument_error", "and", v, "expected [_, _]") unless pair?(v) @interp.truthy?(v[0]) && @interp.truthy?(v[1]) end |
#chars(v) ⇒ Object
186 187 188 189 190 191 |
# File 'lib/fusion/interpreter/builtins.rb', line 186 def chars(v) return v if v.is_a?(ErrorVal) return error("type_error", "chars", v, "expected a string") unless v.is_a?(String) v.chars end |
#concat(v) ⇒ Object
178 179 180 181 182 183 184 |
# File 'lib/fusion/interpreter/builtins.rb', line 178 def concat(v) return v if v.is_a?(ErrorVal) return error("argument_error", "concat", v, "expected [_, _]") unless pair?(v) return error("type_error", "concat", v, "expected strings") unless v[0].is_a?(String) && v[1].is_a?(String) v[0] + v[1] end |
#divide(v) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/fusion/interpreter/builtins.rb', line 81 def divide(v) return v if v.is_a?(ErrorVal) return error("argument_error", "divide", v, "expected [_, _]") unless pair?(v) return error("type_error", "divide", v, "expected numbers") unless numeric?(v[0]) return error("type_error", "divide", v, "expected numbers") unless numeric?(v[1]) return error("math_error", "divide", v, "division by zero") if v[1] == 0 a, b = v if a.is_a?(Integer) && b.is_a?(Integer) && (a % b).zero? a / b else a.to_f / b end end |
#equals(v) ⇒ Object
— comparison —
123 124 125 126 127 128 |
# File 'lib/fusion/interpreter/builtins.rb', line 123 def equals(v) return v if v.is_a?(ErrorVal) return error("argument_error", "equals", v, "expected [_, _]") unless pair?(v) @interp.deep_equal?(v[0], v[1]) end |
#floor(v) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/fusion/interpreter/builtins.rb', line 113 def floor(v) return v if v.is_a?(ErrorVal) return error("type_error", "floor", v, "expected a number") unless numeric?(v) return error("math_error", "floor", v, "not a finite number") if non_finite?(v) v.floor end |
#get(v) ⇒ Object
Read from an array (integer index, negative counts from the end) or an object (string key) — mirroring the ‘[]` operator (reference §8).
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/fusion/interpreter/builtins.rb', line 247 def get(v) return v if v.is_a?(ErrorVal) return error("argument_error", "get", v, "expected [_, _]") unless pair?(v) container, key = v if container.is_a?(Array) && key.is_a?(Integer) i = key.negative? ? container.length + key : key return container[i] if i >= 0 && i < container.length error("access_error", "get", v, "index out of range") elsif container.is_a?(Hash) && key.is_a?(String) return container[key] if container.key?(key) error("access_error", "get", v, "missing key") else error("type_error", "get", v, "bad index type") end end |
#install(table, interp) ⇒ Object
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 |
# File 'lib/fusion/interpreter/builtins.rb', line 10 def install(table, interp) @interp = interp define = ->(name, fn) { table[name] = NativeFunc.new(name, fn) } # operations on a pair [a, b] (or a single value) define.call("add", method(:add)) define.call("subtract", method(:subtract)) define.call("multiply", method(:multiply)) define.call("divide", method(:divide)) define.call("mod", method(:mod)) define.call("negate", method(:negate)) define.call("floor", method(:floor)) define.call("equals", method(:equals)) define.call("lessThan", method(:less_than)) define.call("and", method(:and_)) define.call("or", method(:or_)) define.call("not", method(:not_)) define.call("length", method(:length)) define.call("concat", method(:concat)) define.call("chars", method(:chars)) define.call("join", method(:join)) define.call("toString", method(:to_string)) define.call("parseNumber", method(:parse_number)) define.call("keys", method(:keys)) define.call("values", method(:values)) define.call("get", method(:get)) define.call("set", method(:set)) define.call("toObject", method(:to_object)) # type predicates: return false on any non-matching value, never an error define.call("Integer", method(:integer?)) define.call("Float", method(:float?)) define.call("Number", method(:numeric?)) define.call("String", method(:string?)) define.call("Boolean", method(:boolean?)) define.call("Array", method(:array?)) define.call("Object", method(:object?)) define.call("Null", method(:null?)) define.call("Function", method(:function?)) define.call("NonFinite", method(:non_finite?)) end |
#join(v) ⇒ Object
193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/fusion/interpreter/builtins.rb', line 193 def join(v) return v if v.is_a?(ErrorVal) return error("argument_error", "join", v, "expected [_, _]") unless pair?(v) array, separator = v unless array.is_a?(Array) && separator.is_a?(String) && array.all? { |item| item.is_a?(String) } return error("type_error", "join", v, "expected [array-of-strings, separator-string]") end array.join(separator) end |
#keys(v) ⇒ Object
— object key enumeration (Tier 0: patterns can’t enumerate unknown keys) —
231 232 233 234 235 236 |
# File 'lib/fusion/interpreter/builtins.rb', line 231 def keys(v) return v if v.is_a?(ErrorVal) return error("type_error", "keys", v, "expected an object") unless v.is_a?(Hash) v.keys end |
#length(v) ⇒ Object
— strings and structure bridges —
171 172 173 174 175 176 |
# File 'lib/fusion/interpreter/builtins.rb', line 171 def length(v) return v if v.is_a?(ErrorVal) return error("type_error", "length", v, "expected a string, array, or object") unless v.is_a?(String) || v.is_a?(Array) || v.is_a?(Hash) v.length end |
#less_than(v) ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/fusion/interpreter/builtins.rb', line 130 def less_than(v) return v if v.is_a?(ErrorVal) return error("argument_error", "lessThan", v, "expected [_, _]") unless pair?(v) a, b = v if numeric?(a) && numeric?(b) a < b elsif a.is_a?(String) && b.is_a?(String) a < b else error("type_error", "lessThan", v, "expected two numbers or two strings") end end |
#mod(v) ⇒ Object
96 97 98 99 100 101 102 103 104 |
# File 'lib/fusion/interpreter/builtins.rb', line 96 def mod(v) return v if v.is_a?(ErrorVal) return error("argument_error", "mod", v, "expected [_, _]") unless pair?(v) return error("type_error", "mod", v, "expected numbers") unless numeric?(v[0]) return error("type_error", "mod", v, "expected numbers") unless numeric?(v[1]) return error("math_error", "mod", v, "modulo by zero") if v[1] == 0 v[0] % v[1] end |
#multiply(v) ⇒ Object
72 73 74 75 76 77 78 79 |
# File 'lib/fusion/interpreter/builtins.rb', line 72 def multiply(v) return v if v.is_a?(ErrorVal) return error("argument_error", "multiply", v, "expected [_, _]") unless pair?(v) return error("type_error", "multiply", v, "expected numbers") unless numeric?(v[0]) return error("type_error", "multiply", v, "expected numbers") unless numeric?(v[1]) v[0] * v[1] end |
#negate(v) ⇒ Object
106 107 108 109 110 111 |
# File 'lib/fusion/interpreter/builtins.rb', line 106 def negate(v) return v if v.is_a?(ErrorVal) return error("type_error", "negate", v, "expected a number") unless numeric?(v) -v end |
#not_(v) ⇒ Object
163 164 165 166 167 |
# File 'lib/fusion/interpreter/builtins.rb', line 163 def not_(v) return v if v.is_a?(ErrorVal) !@interp.truthy?(v) end |
#or_(v) ⇒ Object
156 157 158 159 160 161 |
# File 'lib/fusion/interpreter/builtins.rb', line 156 def or_(v) return v if v.is_a?(ErrorVal) return error("argument_error", "or", v, "expected [_, _]") unless pair?(v) @interp.truthy?(v[0]) || @interp.truthy?(v[1]) end |
#parse_number(v) ⇒ Object
218 219 220 221 222 223 224 225 226 227 |
# File 'lib/fusion/interpreter/builtins.rb', line 218 def parse_number(v) return v if v.is_a?(ErrorVal) return error("type_error", "parseNumber", v, "expected a string") unless v.is_a?(String) case v when /\A-?\d+\z/ then v.to_i when /\A-?\d+(\.\d+)?([eE][+-]?\d+)?\z/ then v.to_f else error("conversion_error", "parseNumber", v, "not a numeric string") end end |
#set(v) ⇒ Object
Return a new array/object with one entry set. An array index must already exist (arrays are not extended); an object key may be new. Addressing mirrors ‘@get` (array by integer index, object by string key).
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/fusion/interpreter/builtins.rb', line 269 def set(v) return v if v.is_a?(ErrorVal) return error("argument_error", "set", v, "expected [_, _, _]") unless v.is_a?(Array) && v.length == 3 container, key, value = v if container.is_a?(Array) && key.is_a?(Integer) i = key.negative? ? container.length + key : key return error("access_error", "set", v, "index out of range") unless i >= 0 && i < container.length container.dup.tap { |copy| copy[i] = value } elsif container.is_a?(Hash) && key.is_a?(String) container.merge(key => value) else error("type_error", "set", v, "bad index type") end end |
#subtract(v) ⇒ Object
63 64 65 66 67 68 69 70 |
# File 'lib/fusion/interpreter/builtins.rb', line 63 def subtract(v) return v if v.is_a?(ErrorVal) return error("argument_error", "subtract", v, "expected [_, _]") unless pair?(v) return error("type_error", "subtract", v, "expected numbers") unless numeric?(v[0]) return error("type_error", "subtract", v, "expected numbers") unless numeric?(v[1]) v[0] - v[1] end |
#to_object(v) ⇒ Object
286 287 288 289 290 291 292 293 294 |
# File 'lib/fusion/interpreter/builtins.rb', line 286 def to_object(v) return v if v.is_a?(ErrorVal) return error("type_error", "toObject", v, "expected an array") unless v.is_a?(Array) unless v.all? { |entry| pair?(entry) && entry[0].is_a?(String) } return error("type_error", "toObject", v, "expected [string, value] entries") end v.to_h end |
#to_string(v) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/fusion/interpreter/builtins.rb', line 205 def to_string(v) return v if v.is_a?(ErrorVal) case v when String then v when Integer, Float then v.to_s when true then "true" when false then "false" when NULL then "null" else error("conversion_error", "toString", v, "cannot stringify this value type") end end |
#values(v) ⇒ Object
238 239 240 241 242 243 |
# File 'lib/fusion/interpreter/builtins.rb', line 238 def values(v) return v if v.is_a?(ErrorVal) return error("type_error", "values", v, "expected an object") unless v.is_a?(Hash) v.values end |