Eiffel: способ оценить выражение STRING, например, `eval` - PullRequest
0 голосов
/ 10 октября 2018

Есть ли способ оценить выражение STRING в Eiffel?(Я знаю, что это большой источник ошибок ... но мощный механизм!)

В поисках способа создания универсального механизма настройки для полей и классов базы данных я пытаюсь сделать что-то вроде.

fields_mapping: HASH_TABLE [ANY, STRING]
    do
        create Result.make (10)
        Result.put (name, "name")
        Result.put (surname, "surname")
        ...
    end

set_fields
    do
        across
            fields_mapping as field
        loop
            eval("set_" + field.key + "(" + field.item + ")")
        end
    end

Я знаю, что мог бы сделать это с агентами, но мне кажется, что это менее универсально, поскольку я должен определить каждую функцию 2 раза

  • в fields_mapping
  • в другом fields_mapping у меня для преобразования JSON

1 Ответ

0 голосов
/ 10 октября 2018

Существующие реализации Eiffel скорее компилируют, чем интерпретируют.Поэтому оценка произвольных выражений не поддерживается.Обновление произвольных полей объекта с использованием заданных значений по-прежнему возможно с использованием классов отражения:

update_object (field_values: HASH_TABLE [ANY, STRING]; target: ANY)
        -- Update fields of object `target` with values from `field_values`.
    local
        object: REFLECTED_REFERENCE_OBJECT
        fields: like field_properties
        position: like {REFLECTED_OBJECT}.field_count
    do
        create object.make (target)
        fields := field_properties (object.dynamic_type)
        across
            field_values as v
        loop
            if attached fields [v.key] as f then
                position := f.position
                if {REFLECTOR}.field_conforms_to (v.item.generating_type.type_id, f.type_id) then
                    inspect object.field_type (position)
                    when {REFLECTOR_CONSTANTS}.integer_32_type then
                        object.set_integer_32_field (position, {INTEGER_32} / v.item)
                    when ... then
                        -- Other basic types.
                    when {REFLECTOR_CONSTANTS}.reference_type then
                        object.set_reference_field (position, v.item)
                    else
                        print ("Unhandled field type%N")
                    end
                else
                    print ("Field type mismatch%N")
                end
            end
        end
    end

Приведенный выше код немного упрощен, поскольку он не обрабатывает типы SPECIAL и TUPLE, а также расширяемые пользователемтипы.Код опирается на вспомогательную функцию, которая записывает информацию о типе, так что в следующий раз ее не придется заново вычислять с нуля:

field_properties (type_id: like {TYPE [ANY]}.type_id):
    HASH_TABLE [TUPLE [position: INTEGER; type_id: INTEGER], STRING]
        -- Positions and types of fields indexed by their name
        -- for a specified type ID `type_id`.
    local
        i: like {REFLECTOR}.field_count_of_type
    do
        Result := field_positions_table [type_id]
        if not attached Result then
            from
                i := {REFLECTOR}.field_count_of_type (type_id)
                create Result.make (i)
                field_positions_table.force (Result, type_id)
            until
                i <= 0
            loop
                Result [{REFLECTOR}.field_name_of_type (i, type_id)] :=
                    [i, {REFLECTOR}.field_static_type_of_type (i, type_id)]
                i := i - 1
            end
        end
    end

field_positions_table: HASH_TABLE [HASH_TABLE
    [TUPLE [position: INTEGER; type_id: INTEGER], STRING], INTEGER]
    once
        create Result.make (1)
    end

Используя функцию update_object и предполагая, что объект x имеет поля fooи bar типов INTEGER_32 и detachable STRING_8 соответственно, следующий код

        field_values: HASH_TABLE [ANY, STRING]
    do
        create field_values.make (10)
        field_values ["foo"] := {INTEGER_32} 5
        field_values ["bar"] := " bottles"
        update_object (field_values, x)
        print (x.foo)
        print (x.bar)

выведет 5 bottles независимо от предыдущего состояния объекта x.

...