Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Я не совсем идею понял. Почему тебя не волнует правильность исходных данных?
С чего ты взял что не волнует?
ANS> И всё таки, если прохождение валидации не гарантирует правильность целевого кода, то зачем она нужна?
Она гарантирует правильность его структуры. Так, что при написании генератора мне не надо заботится о его корректном поведении при нарушенной структуре.
ANS>Если речь идёт о внутрипрограмной генерации, то не проще ли создать генератор с неким API. Который, можно протестировать.
Не проще. Поскольку написание генератора не самоцель, а всего лишь промежуточный шаг. Тестировать его тщательно бессмысленно, покольку он используется для ограниченного набора use-cases.
ANS> У тебя будет одна точка, где может возникнуть ошибка, а не три.
Здравствуйте, andyJB, Вы писали:
JB>Здравствуйте, VladD2, Вы писали:
VD>>Покажи как будет выглядить пример с генерацией свойсатв на CamlP4 и Ocaml-е. Думаю, тут всем будет интересно.
JB>А можно ссылку на пример, который нужно переписать?
А понял, из предыдущего ответа.
Здравствуйте, AndrewVK, Вы писали:
AVK>А можно увидеть на лиспе решение следующей задачи: AVK>Имеем некое текстовое описание модели каких либо объектов.
Возможно обчеству будет интересно как это было бы удобно делать на Питоне:
Код генератора (test.py):
classCSClass(object):
@classmethod
def genSharpCode(csclass):
props = sorted((n, desc.tp_name) for n, desc in vars(csclass).items() if isinstance(desc, CSProp))
# заголовок класса
code = "public class %s\n" % csclass.__name__
code += "{\n"# конструктор
code += "\tpublic %s(%s)\n" % (csclass.__name__, ", ".join("%s %s" % (t, n) for n, t in props))
code += "\t{\n"for name, _ in props:
code += "\t\t_%s = %s;\n" % (name, name)
code += "\t}\n"# свойстваfor name, typ in props:
code += ("\n\tprivate %(typ)s _%(name)s;\n\n" +
"\tpublic %(typ)s %(name)s\n" +
"\t{\n" +
"\t\tget { return _%(name)s; }\n" +
"\t}\n") % vars()
code += "}"return code
classCSProp(property):
def __init__(self, typ):
self.tp_name = typ.__name__
# объявления поддерживаемых типов свойств (типы int и bool - не описываю, т.к. они уже есть в питоне под нужными именами)class string(str): pass
class double(float): pass
# разбор параметров запуска
import sys
module = {}
eval(compile(file(sys.argv[1]).read(), sys.argv[1], "exec"), globals(), module)
for csclass in module.itervalues():
if issubclass(csclass, CSClass):
print csclass.genSharpCode()
фaйл исходных данных (test.classes):
class Obj1(CSClass):
prop1 = CSProp(int)
prop2 = CSProp(bool)
class Obj2(CSClass):
prop3 = CSProp(string)
prop4 = CSProp(double)
запускать так:
d:\>python test.py test.classes
Обратите внимание, что для разрешения имен элементов/атрибутов/типов-свойств используется сам интерпретатор питона, который, попутно, очень даже замечательно их все и валидирует.
Результат:
public class Obj1
{
public Obj1(int prop1, bool prop2)
{
_prop1 = prop1;
_prop2 = prop2;
}
private int _prop1;
public int prop1
{
get { return _prop1; }
}
private bool _prop2;
public bool prop2
{
get { return _prop2; }
}
}
public class Obj2
{
public Obj2(string prop3, double prop4)
{
_prop3 = prop3;
_prop4 = prop4;
}
private string _prop3;
public string prop3
{
get { return _prop3; }
}
private double _prop4;
public double prop4
{
get { return _prop4; }
}
}
AVK>Интересует решение именно в духе лиспа.
Кстати, да — вполне в лисповском духе получилось...
1. На сколько хорош LispWorks Personal Edition? Я так понимаю LispWorks всем лучше LispBox, только он платный ?
2. Можно ли создать исполняемый *.exe модуль программы на лиспе.
3. Cкачал LispBox — не работает OpenFile. Просто какой-то писк, словно ошибка произошла и все.
Что делать?
4. JabberWokly — лажа ?
Здравствуйте, fionbio, Вы писали:
F>Напоследок приведу ссылку на одну интересную вещь — пример работы с Common Lisp, F>в режиме самого что ни на есть interactive development'а. Я уже давал ссылку на F>статью известного деятеля в области OO, XP и пр. Martin'а Fowler'а: F>http://martinfowler.com/articles/languageWorkbench.html
Я скачал ListWorks, и посмотрел на examples, но даже не смог из запустить. Т.е. не понятно ничего вообще...
Качать мувик не хочется, хочется прочитать и самому написать DSL, пободный JetBrainsсовскому HelloWorld, чтобы
сравнить.
Здравствуйте, VladD2, Вы писали:
E>>Кстати, да — вполне в лисповском духе получилось... VD>Агащазблин. Чистый императив как на Руби, только вместо ХМЛ-я непойми что.
Ну, там же написано "в лисповском духе", а не "чисто декларативный разборщик DSL" — почувствуй разницу. Под "лисповским духом" я тут имел ввиду, что в качестве формата исходных данных был использован сам язык высокого уровня (Internal DSL, в определении Фаулера).
Что же касается "ХМЛ" vs "непойми что", то сдается мне ты лукавишь.
Вот это:
class Obj1(CSClass):
prop1 = CSProp(int)
prop2 = CSProp(string)
Здравствуйте, eugals, Вы писали:
E>Здравствуйте, VladD2, Вы писали:
E>>>Кстати, да — вполне в лисповском духе получилось... VD>>Агащазблин. Чистый императив как на Руби, только вместо ХМЛ-я непойми что.
E>Ну, там же написано "в лисповском духе", а не "чисто декларативный разборщик DSL" — почувствуй разницу.
Думаю "в лисповском духе" как раз и подразумевает декларативность. Можно спросить у АВК.
E> Под "лисповским духом" я тут имел ввиду, что в качестве формата исходных данных был использован сам язык высокого уровня
Думаю, что это как раз самое плохое в лисповском коде.
E>Что же касается "ХМЛ" vs "непойми что", то сдается мне ты лукавишь.
Здравствуйте, AndrewVK, Вы писали:
AVK>А можно увидеть на лиспе решение следующей задачи: AVK>Имеем некое текстовое описание модели каких либо объектов. Пусть это будет xml. Например:
Быть может, уже поздно. Но хочу предложить свое решение на Ruby
class MyObject
def initialize(name)
@name = name
@propertys = []
end
def to_s
str = ""
str += "public class #@name\n"
str += "{\n"
str += " public #@name("
@propertys.each_index { |x|
str += "#{@propertys[x]['type']} #{@propertys[x]['name']}"
str += ", " if x < @propertys.length - 1
}
str += ")\n"
str += " {\n"
@propertys.each { |item|
str += " _#{item['name']} = #{item['name']};\n"
}
str += " }\n"
@propertys.each { |item|
str += " \n"
str += " private #{item['type']} _#{item['name']};\n\n"
str += " public #{item['type']} #{item['name'].capitalize}\n"
str += " {\n"
str += " get { return _#{item['name']}; } \n"
str += " }\n"
}
str += "}\n"
end
def AddProperty(type, name)
@propertys += [ { 'type' => type, 'name' => name } ]
end
end
def _object(name)
$obj = MyObject.new(name)
yield
print $obj
end
def _property(type, name)
$obj.AddProperty(type, name)
end
# описание модели
_object("Obj1") {
_property("int", "prop1")
_property("string", "prop2")
}
Выводит:
public class Obj1
{
public Obj1(int prop1, string prop2)
{
_prop1 = prop1;
_prop2 = prop2;
}
private int _prop1;
public int Prop1
{
get { return _prop1; }
}
private string _prop2;
public string Prop2
{
get { return _prop2; }
}
}
Итак, руби -- язык интерпретируемый? Значит можно написать всё на самом языке... Надеюсь я понятно выразился
Ps. Это мой первый опыт программирования на руби. Буквально сегодня я начал его изучать, прочитал пока пару статей...
Здравствуйте, pongo, Вы писали:
P>Ps. Это мой первый опыт программирования на руби. Буквально сегодня я начал его изучать, прочитал пока пару статей...
Ура!!! Полку Rubyist-ов на RSDN прибывает!
Позволю себе пару комментариев по твоему посту. Во-первых, ты выбрал не самый удачный вариант DSL. Можно было бы сделать либо так:
.
Ну и в твоем варианте можно было вполне обойтись без глобальной переменной.
Во-вторых, Ruby, имхо, лучше изучать не по статьям, а по книге "Programming Ruby: The Pragmatic Programmer's Guide". Ее первое издание свободно доступно на rubycentral.com и, более того, идет в OneClickRubyInstaller. Недавно вышло второе издание. В электронном виде (PDF) доступно только через eMule . Но, имхо, даже первое издание дает очень хорошее представление о языке и о том, как его можно использовать. Например, год назад, имея под рукой только первое издание, я сделал свой Mxx_ru, а там Ruby как раз в качестве DSL и применяется.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Позволю себе пару комментариев по твоему посту.
я сделал так, как позволили мои знания. В общем, надо будет это изучить
E>Ну и в твоем варианте можно было вполне обойтись без глобальной переменной.
Знаю.
E>Во-вторых, Ruby, имхо, лучше изучать не по статьям, а по книге "Programming Ruby: The Pragmatic Programmer's Guide".
до неё я еще не дошел. Как не дошел и до DSL. Читал про DSL только маленькую статью в одном блоге...
Смеха ради можно попользовать макросы из С. Прогонять только препроцессором.
Вот программа:
#define CLASS(name, properties)\
public class name {\
properties\
}
#define BASE(name) : name
#define PROP(type, name)\
type _##name;\
type name { \
get {return _##name; }\
set { _##name = value; }\
}
был проявлен интерес к тому, как решение подобной задачи могло выглядеть на Ruby (Ruby как DSL вместо XML, результирующий код так же генерируется для Ruby).
# Подключаем Pretty Printer для печати содержимого объектов.
require 'pp'### Начало реализации DSL
# Объект этого типа будет аккумулировать метаописание.class ObjectDesc
attr_reader :name
attr_reader :properties
def initialize( name )
@name = name
@properties = []
end
def property( name )
@properties << name
end
end# Генератор описания класса из метаописания.def generate( o )
c = %Q{
class#{o.name}
#{o.properties.inject('') { |r,p| r << " attr_accessor :#{p}\n"; r }}def initialize( #{o.properties.join(', ')} )
#{o.properties.inject('') { |r,p| r << " @#{p} = #{p}\n"; r }}end
end
}
c
end# Это и есть элемент специализированного DSL-я.def object( name, &blk )
o = ObjectDesc.new( name )
o.instance_eval( &blk )
eval generate( o )
end### Начало использования DSL
# Задаем метаописание пустого класса посредством DSL.
object "Empty"do
end# Задаем метаописание первого класса посредством DSL.
object "First"do
property :first
property :second
property :a
end### Проверка того, что класс Fisrt действительно доступен для разработчика.
# Работаем с уже определенным классом.
f = First.new( 'a', 'b', 'c' )
pp f
f.first = "aa"
f.second = "bb"
pp f
Собственно сам DSL -- это обращение к функции object:
object "First"do
property :first
property :second
property :a
end
из которого функция generate создает текст вида:
class First
attr_accessor :first
attr_accessor :second
attr_accessor :a
def initialize( first, second, a )
@first = first
@second = second
@a = a
end
end
а функция object вычисляет его через eval. Таким образом, внутри object() описание нового класса становится доступным для Ruby-программы.
Функция generate могла иметь и чуть более простой вид (с меньшим количеством обращений к string interpolation):
def generate( o )
c = String.new
c << "class #{o.name}\n"
o.properties.each { |p| c << " attr_accessor :#{p}\n" }
c << " def initialize( #{o.properties.join(', ')} )\n"
o.properties.each { |p| c << " @#{p} = #{p}\n" }
c << " end\n"
c << "end\n"
c
end
к тому же она строит код без лишних пустых строк:
class First
attr_accessor :first
attr_accessor :second
attr_accessor :a
def initialize( first, second, a )
@first = first
@second = second
@a = a
end
end
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Cyberax, Вы писали:
>> C>В-третьих, для обычных языков типа Java/C# уже существуют системы для >> C>редактирования AST. Только называется это Aspect Oriented >> Programming. А >> C>для C# у нас еще и R# есть >> Не есть — а недавно появилось...
Ваши представления об АОП несколько искажены.
C>AspectJ появился в 99 (если не ошибаюсь), до этого были исследования на C>эту тему в PARC'е.
>> Что еше раз потверждает выше сказанную мысль о том что все языки >> медленно двигаются в сторону Лиспа. >> Меня собственно и подвигло на серьезноге изучение Лиспа, так это то >> что в CLOS кажись заложенно и AOP .
C>Кстати, после нескольких лет увлечения AOP сейчас интерес к нему C>угасает.
был проявлен интерес к тому, как решение подобной задачи могло выглядеть на Ruby (Ruby как DSL вместо XML, результирующий код так же генерируется для Ruby).
Спасибо за код. Я так понял, что Ruby — язык с динамической типизацией?
В общем-то, не нравится мне в его средствах метапрограммирования то, что они недалеко ушли от сишных макросов — фактически мы собираем код в текстовом виде. Со всеми вытекающими в виде отсутствия контроля типов в компайл-тайм (но в Ruby-то этого и так нет, если я всё правильно понимаю) и невнятных ошибок в случае, если что-то генерится неверно (на простом примере можно и глазками посмотреть, а вот на сложном...).
Ну и ещё не нравится то, что нельзя оперировать кусками AST, т.к. это может быть очень полезно (ну там — пройтись по AST рекурсивно и сделать что-нибудь для нодов определённого типа). Или можно, но в коде это не использовалось?
Ну а нравится, соответственно, неограниченная гибкость — пиши что хочешь и как хочешь. В общем, макросы Nemerle — это строготипизированный подход к метапрограммированию