Skip to content

Commit

Permalink
add 'List' class
Browse files Browse the repository at this point in the history
  • Loading branch information
taichi-ishitani committed Jul 23, 2024
1 parent 2b99864 commit 43d000d
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 70 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Style/Alias:
Style/EmptyMethod:
EnforcedStyle: expanded

Style/HashAsLastArrayItem:
EnforcedStyle: no_braces

Style/RaiseArgs:
EnforcedStyle: compact

Expand Down
2 changes: 2 additions & 0 deletions lib/rupkl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
require_relative 'rupkl/node/boolean'
require_relative 'rupkl/node/number'
require_relative 'rupkl/node/string'
require_relative 'rupkl/node/collection'
require_relative 'rupkl/node/list'
require_relative 'rupkl/node/object'
require_relative 'rupkl/node/dynamic'
require_relative 'rupkl/node/mapping'
Expand Down
8 changes: 6 additions & 2 deletions lib/rupkl/node/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ def add_builtin_class(klass)
add_builtin_class PklModule

define_builtin_property(:NaN) do
Float.new(parent, ::Float::NAN, position)
Float.new(self, ::Float::NAN, position)
end

define_builtin_property(:Infinity) do
Float.new(parent, ::Float::INFINITY, position)
Float.new(self, ::Float::INFINITY, position)
end

define_builtin_method(:List, elements: [Any, varparams: true]) do |elements|
List.new(nil, elements, nil)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/rupkl/node/boolean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ def short_circuit?(operator)

define_builtin_method(:xor, other: Boolean) do |other|
result = value ^ other.value
Boolean.new(nil, result, position)
Boolean.new(nil, result, nil)
end

define_builtin_method(:implies, other: Boolean) do |other|
result = !value || other.value
Boolean.new(nil, result, position)
Boolean.new(nil, result, nil)
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/rupkl/node/collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module RuPkl
module Node
class Collection < Any
abstract_class
uninstantiable_class
end
end
end
8 changes: 4 additions & 4 deletions lib/rupkl/node/dynamic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@ def find_by_key(key)

define_builtin_method(:length) do
result = elements&.size || 0
Int.new(nil, result, position)
Int.new(nil, result, nil)
end

define_builtin_method(:hasProperty, name: String) do |name|
result = find_property(name.value.to_sym) && true || false
Boolean.new(nil, result, position)
Boolean.new(nil, result, nil)
end

define_builtin_method(:getProperty, name: String) do |name|
find_property(name.value.to_sym) ||
begin
m = "cannot find property '#{name.value}'"
raise EvaluationError.new(m, position)
raise EvaluationError.new(m, nil)
end
end

define_builtin_method(:getPropertyOrNull, name: String) do |name|
find_property(name.value.to_sym) || Null.new(nil, position)
find_property(name.value.to_sym) || Null.new(nil, nil)
end

private
Expand Down
15 changes: 15 additions & 0 deletions lib/rupkl/node/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module RuPkl
module Node
class List < Collection
uninstantiable_class

def initialize(parent, elements, position)
super(parent, *elements, position)
end

alias_method :elements, :children
end
end
end
2 changes: 1 addition & 1 deletion lib/rupkl/node/listing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def find_by_key(key)
elements
&.map { _1.value.to_string }
&.join(separator.value)
String.new(nil, result || '', nil, position)
String.new(nil, result || '', nil, nil)
end

private
Expand Down
4 changes: 2 additions & 2 deletions lib/rupkl/node/mapping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ def find_by_key(key)

define_builtin_method(:containsKey, key: Any) do |key|
result = find_entry(key) && true || false
Boolean.new(nil, result, position)
Boolean.new(nil, result, nil)
end

define_builtin_method(:getOrNull, key: Any) do |key|
find_entry(key) || Null.new(nil, position)
find_entry(key) || Null.new(nil, nil)
end

private
Expand Down
78 changes: 66 additions & 12 deletions lib/rupkl/node/method_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ def initialize(parent, name, type, position)
def check_type(value, context, position)
type&.check_type(value, context, position)
end

def varparam?
false
end
end

class VariadicMethodParam < MethodParam
def check_type(values, context, position)
values.each { |v| super(v, context, position) }
end

def varparam?
true
end
end

class MethodDefinition
Expand All @@ -38,33 +52,50 @@ def initialize(parent, name, params, type, body, position)
def call(receiver, arguments, context, position)
args = evaluate_arguments(arguments, context, position)
execute_method(receiver, args)
.tap { |result| overwrite_position(result, position) }
end

private

def evaluate_arguments(arguments, context, position)
check_arity(arguments, position)

arguments&.zip(params)&.map do |arg, param|
evaluate_argument(arg, param, context)
params&.map&.with_index do |param, i|
arg =
if param.varparam?
Array(arguments&.[](i..))
else
arguments&.[](i)
end
evaluate_argument(param, arg, context)
end
end

def evaluate_argument(arg, param, context)
value = arg.evaluate(context)
param.check_type(value, context, position)
[param.name, value]
end

def check_arity(arguments, position)
n_args = arguments&.size || 0
n_params = params&.size || 0
return if n_args == n_params
n_params = n_params_range
return if n_args in ^n_params

m = "expected #{n_params} method arguments but got #{n_args}"
raise EvaluationError.new(m, position)
end

def n_params_range
n_params = params&.size || 0
params&.last&.varparam? && (n_params - 1..) || n_params
end

def evaluate_argument(param, arg, context)
value =
if param.varparam?
arg.map { _1.evaluate(context) }
else
arg.evaluate(context)
end
param.check_type(value, context, position)
[param.name, value]
end

def execute_method(receiver, arguments)
context = create_call_context(receiver, arguments)
execute_body(context)
Expand All @@ -85,6 +116,10 @@ def execute_body(context)
.evaluate(context)
.tap { type&.check_type(_1, context, position) }
end

def overwrite_position(result, position)
result.instance_exec(position) { @position = _1 }
end
end

class MethodCallContext
Expand Down Expand Up @@ -125,16 +160,35 @@ def initialize(name, klass)
end
end

class BuiltinVariadicMethodParam < VariadicMethodParam
def initialize(name, klass)
id = Identifier.new(nil, name, nil)
type = BuiltinMethodTypeChecker.new(klass)
super(nil, id, type, nil)
end
end

class BuiltinMethodDefinition < MethodDefinition
def initialize(name, **params, &body)
param_list = params.map { |n, t| BuiltinMethodParams.new(n, t) }
id = Identifier.new(nil, name, nil)
super(nil, id, param_list, nil, nil, nil)
list = param_list(params)
super(nil, id, list, nil, nil, nil)
@body = body
end

private

def param_list(params)
params.map do |name, type|
case type
in [klass, { varparams: true }]
BuiltinVariadicMethodParam.new(name, klass)
else
BuiltinMethodParams.new(name, type)
end
end
end

def execute_method(receiver, arguments)
receiver.instance_exec(*arguments&.map(&:last), &body)
end
Expand Down
24 changes: 12 additions & 12 deletions lib/rupkl/node/number.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,32 @@ def force_float?(operator, r_operand)
end

define_builtin_method(:toString) do
String.new(nil, value.to_s, nil, position)
String.new(nil, value.to_s, nil, nil)
end

define_builtin_method(:toInt) do
Int.new(nil, value.to_i, position)
Int.new(nil, value.to_i, nil)
end

define_builtin_method(:toFloat) do
Float.new(nil, value.to_f, position)
Float.new(nil, value.to_f, nil)
end

define_builtin_method(:round) do
result = value.finite? && value.round || value
self.class.new(nil, result, position)
self.class.new(nil, result, nil)
end

define_builtin_method(:truncate) do
result = value.finite? && value.truncate || value
self.class.new(nil, result, position)
self.class.new(nil, result, nil)
end

define_builtin_method(:isBetween, first: Number, last: Number) do |f, l|
result =
[f.value, l.value, value].all? { _1.finite? || _1.infinite? } &&
(f.value..l.value).include?(value)
Boolean.new(nil, result, position)
Boolean.new(nil, result, nil)
end
end

Expand All @@ -127,12 +127,12 @@ def initialize(parent, value, position)

define_builtin_method(:shl, n: Int) do |n|
result = value << n.value
self.class.new(self, result, position)
self.class.new(self, result, nil)
end

define_builtin_method(:shr, n: Int) do |n|
result = value >> n.value
self.class.new(self, result, position)
self.class.new(self, result, nil)
end

define_builtin_method(:ushr, n: Int) do |n|
Expand All @@ -143,19 +143,19 @@ def initialize(parent, value, position)
else
value >> n.value
end
self.class.new(self, result, position)
self.class.new(self, result, nil)
end

define_builtin_method(:and, n: Int) do |n|
self.class.new(nil, value & n.value, position)
self.class.new(nil, value & n.value, nil)
end

define_builtin_method(:or, n: Int) do |n|
self.class.new(nil, value | n.value, position)
self.class.new(nil, value | n.value, nil)
end

define_builtin_method(:xor, n: Int) do |n|
self.class.new(nil, value ^ n.value, position)
self.class.new(nil, value ^ n.value, nil)
end
end

Expand Down
Loading

0 comments on commit 43d000d

Please sign in to comment.