Я ищу различные подходы для поддержки некоторого уровня intellisense на динамически типизированном языке. С тех пор intellisense информация основан на информации о типе, существуют свойственные трудности при реализации этого для динамических языков.
Вы знаете, что какие-либо алгоритмы или методы реализуют его?
Вам нужно написать абстрактный интерпретатор , который выполняет код со значениями типов. Таким образом, вы переходите со своим абстрактным интерпретатором через AST и записываете для каждой переменной отправленные сообщения или известные типы. И когда вы закончите, вы делаете вывод о возможных типах, используя эквивалентность структурных типов (также известную как утиная типизация).
PS: в дополнение к выводу типа вы можете посмотреть «Как история программы может улучшить завершение кода» Ромена Роббса , где объясняется, как еще больше улучшить автоматическое завершение в динамическом режиме. языки с самой последней используемой информацией и совместной фильтрацией.
Итак, вот как абстрактная интерпретация работает для фрагмента кода, такого как
def groups(array,&block)
groups = Hash.new
array.each { |ea|
key = block.call(ea)
groups[key] = [] unless groups.include? key
groups[key] << ea
}
return groups
end
, вы должны начать с
array = { :messages => [], :types => [] }
block = { :messages => [], :types => [] }
, затем
array = { :messages => [], :types => [] }
block = { :messages => [], :types => [] }
groups = { :messages => [], :types => [Hash] }
, затем
array = { :messages => [:each], :types => [] }
block = { :messages => [], :types => [] }
groups = { :messages => [], :types => [Hash] }
, затем
array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [], :types => [Hash] }
key = { :messages => [], :types => [] }
, а затем
array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [:include?,:[]], :types => [Hash] }
group_elements = { :messages => [], :types => [Array] }
key = { :messages => [], :types => [] }
, а затем
array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [:include?,:[]], :types => [Hash] }
group_elements = { :messages => [:<<], :types => [Array] }
key = { :messages => [], :types => [] }
так что в конечном итоге мы можем сделать вывод, что
массив
, возможно, Перечислимый
блок
, возможно, Proc
группы
- это Хэш
с Массив
элементы ключ
- любой объект Я бы скачал исходники плагина Groovy для затмения, он обладает интеллектом (насколько это возможно), и считаю Groovy хорошим образцом дианамического языка с динамической опечаткой
.Легко, нужно добавить только один дополнительный шаг - вывод типа . После этого вы знаете информацию о типе и можете кое-что подсказать пользователю.
.Обратите внимание, что "динамический язык" и "язык с динамическим набором" не обязательно одно и то же.
То, как Microsoft справляется с этим в интеллигенции для Javascript (VS2008), заключается в том, что она, в меру своих возможностей, приходит к выводу, какой тип var в настоящее время имеет в своем распоряжении. Если/когда это изменится, следующие ссылки на var будут представлять опции для обновленного типа.
.