Advertisement
Guest User

Untitled

a guest
Nov 20th, 2011
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.64 KB | None | 0 0
  1. import Boo.Lang.Compiler.Ast
  2. import Boo.Lang.Extensions
  3. import Boo.Lang.PatternMatching
  4.  
  5. //это подпроцедура - для избжания дублирования кода в вложенных макросах
  6. //он для всех одинаков
  7. //принимает имя и тип переменной для генерации
  8. macro expander:
  9.    
  10.     case [| expander $name, $type4fld|]:
  11.        
  12.         yield[|
  13.  
  14.             name_ref = ReferenceExpression($name + '_ref')  //внутренняя ссылка
  15.             name_loaded = ReferenceExpression($name + '_loaded') //флаг загружено или нет
  16.            
  17.             block = Persist["data"] as StructDefinition //здесь формируем структуру обмена        
  18.            
  19.             if block is null:
  20.                
  21.                 block = StructDefinition(Name:'exchange_struct')
  22.                 Persist["data"] = block
  23.                
  24.             block.Members.Add(Field(Name: $name, Type : SimpleTypeReference($type4fld), Modifiers :TypeMemberModifiers.Public))
  25.  
  26.             save_block = Persist["save_data"] as Block  //блок спецкода для сохранения строк
  27.            
  28.             if save_block is null:
  29.                
  30.                 save_block = Block()
  31.                 Persist["save_data"] = save_block              
  32.            
  33.             vars = Persist["vars"] as List of Field //сюда регистрируются поля для создания структуры    
  34.            
  35.             if vars is null:
  36.                
  37.                 vars = List of Field()
  38.                 Persist["vars"] = vars
  39.                                            
  40.             vars.Add(Field(Name: name_loaded.ToString(),Type : SimpleTypeReference('bool')))
  41.         |]
  42.  
  43. //тело сохраняемого класа
  44. macro Persist: 
  45.                
  46.     case [| Persist $name |]:
  47.             //блоки описанные выше
  48.             struct_data  = Persist["data"] as StructDefinition
  49.             var_data = Persist["vars"] as List of Field
  50.             save_block = Persist["save_data"] as Block
  51.             x as ClassDefinition
  52.             x = [|
  53.                     partial class $name:                       
  54.                         //метод получения множества классов из плоского массива в базе
  55.                         static def convert_up(datamap as datamap_file, arr as (exchange_struct), delta as int):
  56.                         //delta - смещение мем-блока arr   
  57.                             empty_exchange = exchange_struct()                                                     
  58.                            
  59.                             size_exchange_struct = memblock.size_type(exchange_struct)
  60.                            
  61.                             for st in arr:
  62.                                
  63.                                 if st != empty_exchange:
  64.                                
  65.                                     yield $name(datamap, st, delta)
  66.                                 else:
  67.                                     yield null
  68.                                
  69.                                 delta += size_exchange_struct
  70.                        
  71.                         //преобразование произвольного IEnumerable[X] в массив его структур для записи в базу
  72.                         static def to_array(datamap_ as datamap_file, seq as $name*):
  73.                            
  74.                             lst = List of exchange_struct()
  75.                                    
  76.                             for o in seq:                                                              
  77.                                
  78.                                 if o:
  79.                                     o.datamap = datamap_
  80.                                    
  81.                                     o.save_strings()
  82.                                    
  83.                                     lst.Add(o.exchange)
  84.                                 else:
  85.                                     lst.Add(exchange_struct())
  86.                                
  87.                             return lst.ToArray()
  88.                            
  89.                         //загрузка одного объекта, на который может быть много ссылок
  90.                         static def load(datamap as datamap_file, delta as int) as $name:
  91.                            
  92.                             obj as object
  93.                            
  94.                             return obj if delta == 0 or datamap.map_objects.TryGetValue(delta, obj)                                                        
  95.                            
  96.                             obj = $name(datamap, delta)
  97.                            
  98.                             datamap.map_objects[delta] = obj
  99.                            
  100.                             return obj
  101.                        
  102.                         //метод для считывая объекта из базы. может понабиться при отмене изменений
  103.                         def force_load(replace as bool):
  104.        
  105.                             new_val = $name(datamap, datamap.load[of exchange_struct](address), address)               
  106.                            
  107.                             datamap.map_objects[address] = new_val if replace
  108.                                
  109.                             return new_val
  110.                            
  111.                         def save_null():
  112.                         //метит в массиве как null
  113.                             exchange = exchange_struct()
  114.                            
  115.                             save() if address  
  116.  
  117.                         //сохраняет все строки объекта
  118.                         def save_strings():
  119.                            
  120.                             $save_block
  121.                        
  122.                         //сохраняет объект                      
  123.                         def save():
  124.                            
  125.                             save_strings()
  126.                            
  127.                             datamap.write[of exchange_struct](exchange, address)
  128.                        
  129.                         //файл базы, откуда объект
  130.                         //одновременно можно работать с несколькими базами                      
  131.                         public datamap as datamap_file
  132.                        
  133.                         //смещение в базе                     
  134.                         public address as int
  135.                         //объявление типа структуры
  136.                         $struct_data
  137.                        
  138.                         //сама структура
  139.                         exchange as exchange_struct
  140.                        
  141.                         //остальное тело класса
  142.                         $(Persist.Body)
  143.                        
  144.                         def constructor():
  145.                            
  146.                             pass   
  147.  
  148.                         def constructor(dmap as datamap_file):
  149.                            
  150.                             datamap = dmap
  151.                            
  152.                         def constructor(dmap as datamap_file, add as int):
  153.                            
  154.                             datamap = dmap
  155.                            
  156.                             address = add
  157.                            
  158.                             exchange = datamap.load[of exchange_struct](address)                                                       
  159.                            
  160.                         def constructor(dmap as datamap_file, data_class as exchange_struct, add as int):
  161.                            
  162.                             datamap = dmap
  163.                            
  164.                             exchange = data_class
  165.                            
  166.                             address = add
  167.                        
  168.                 |]
  169.            
  170.             for i in var_data:
  171.                 x.Members.Add(i)
  172.             yield x
  173.    
  174.     //для хранения value объектов   
  175.     macro VAR:             
  176.         case [| VAR $name as $type |]
  177.  
  178.                 if type.ToString() == "bool":
  179.                    
  180.                     type_ex = "bool"
  181.                 else:
  182.                     type_ex = 'int'
  183.                
  184.                 //делаем доступными переменные из expander
  185.                 expander name.ToString(), type_ex
  186.  
  187.                 vars.Add(Field(Name: name_ref.ToString(), Type : type))
  188.                
  189.                 yield [|
  190.                     //простой обмен с полями структуры для чтения-записи
  191.                     $name as $type:
  192.                         get:                                                 
  193.                             return exchange.$name  
  194.                         set:                                                           
  195.                             exchange.$name = value
  196.                    
  197.                 |]
  198.                
  199.    
  200.     macro REFBLOCK:
  201.         //для классов, которые хранятся как структуры, без возможности нескольких ссылок
  202.         //это ускоряет загрузку за счет избежания регистации загруженных объектов
  203.         case [| REFBLOCK $name as $type |]:
  204.            
  205.             expander name.ToString(), 'int'
  206.  
  207.             vars.Add(Field(Name: name_ref.ToString(), Type : type))                                                
  208.            
  209.             gtype = type as GenericTypeReference
  210.            
  211.             assert gtype
  212.                
  213.             //получаем тип элемента, который можем использовать в макрокоде
  214.             elem_type = ReferenceExpression(gtype.GenericArguments[0].ToString())
  215.            
  216.             //получаем тип контейнера, который можем использовать в макрокоде
  217.             container_type = ReferenceExpression(gtype.Name)
  218.            
  219.             //получаем тип struct элементов контейнера
  220.             struct_ref = ReferenceExpression(gtype.GenericArguments[0].ToString() + ".exchange_struct")
  221.                
  222.             yield [|
  223.            
  224.                     $name as $type:
  225.                         get:
  226.                             if not $name_loaded:
  227.                    
  228.                                 $name_loaded = true
  229.                                
  230.                                 if exchange.$name:
  231.                                     //загружаем, преобразовуем в нормальные классы
  232.                                     arr = datamap.load_arr[of $struct_ref](exchange.$name)
  233.                                
  234.                                     $name_ref = $container_type of $elem_type( $elem_type.convert_up(datamap,arr, exchange.$name))
  235.                                 else:
  236.                                     //ссылка нуль, значит контейнер пуст
  237.                                     $name_ref = $container_type of $elem_type()
  238.                                    
  239.                             return $name_ref   
  240.                         set:                                                                   
  241.                             $name_ref = value
  242.                             //записываем в базу, если присваивают новый контейнер
  243.                             datamap.write_arr[of $struct_ref]($elem_type.to_array(datamap, $name_ref), exchange.$name)                 
  244.             |]
  245.                
  246.     macro REFVAL:
  247.         case [| REFVAL $name as $type |]:              
  248.                 //для сохранения массивов value типа, почти 1 в 1 как раньше
  249.                
  250.                 expander name.ToString(), 'int'
  251.  
  252.                 vars.Add(Field(Name: name_ref.ToString(), Type : type))                                                
  253.                
  254.                 gtype = type as GenericTypeReference
  255.                
  256.                 assert gtype
  257.                    
  258.                 elem_type = ReferenceExpression(gtype.GenericArguments[0].ToString())
  259.                
  260.                 container_type = ReferenceExpression(gtype.Name)                                   
  261.                
  262.                 yield [|   
  263.                         $name as $type:
  264.                             get:
  265.                                 if not $name_loaded:           
  266.                        
  267.                                     $name_loaded = true
  268.                                    
  269.                                     if exchange.$name:
  270.                                        
  271.                                         arr = datamap.load_arr[of $elem_type](exchange.$name)
  272.                                    
  273.                                         $name_ref = $container_type of $elem_type(arr)
  274.                                     else:
  275.                                         $name_ref = $container_type of $elem_type()
  276.                                        
  277.                                 return $name_ref   
  278.                             set:                                                                   
  279.                                 $name_ref = value
  280.                                
  281.                                 $name_loaded = true
  282.                                
  283.                                 datamap.write_arr[of $elem_type]($name_ref.ToArray(), exchange.$name)                  
  284.                     |]
  285.  
  286.     //простая ссылка на объект
  287.     macro REF:             
  288.         case [| REF $name as string |]:            
  289.                
  290.                 expander name.ToString(), 'int'
  291.                 //для строк используем спецкод поддержки, потому что они самостоятельные сохраняемые объекты,
  292.                 //запись которых контролируется их хозяином.
  293.                 name_has_saved = ReferenceExpression($name + '_has_saved')
  294.                
  295.                 vars.Add(Field(Name: name_has_saved.ToString(), Type :SimpleTypeReference('bool')))
  296.                
  297.                 vars.Add(Field(Name: name_ref.ToString(), Type :SimpleTypeReference('string')))
  298.                
  299.                 sc = [|
  300.                         if $name_has_saved:
  301.                            
  302.                             datamap.write_string($name_ref, exchange.$name)
  303.                            
  304.                             $name_has_saved = false
  305.                     |]     
  306.                    
  307.                 save_block.Add(sc)
  308.    
  309.                 yield [|                   
  310.                     $name as string:
  311.                         get:
  312.                             if $name_ref is null:                                                  
  313.                                
  314.                                 if exchange.$name:
  315.                                     $name_ref = datamap.load_string(exchange.$name)
  316.                                 else:
  317.                                     $name_ref = ""
  318.                      
  319.                             return $name_ref   
  320.                         set:
  321.                             $name_has_saved = true
  322.                                
  323.                             $name_ref = value                                                                                  
  324.                 |]
  325.        
  326.         //простая ссылка на другой Persist класс или контейнер с Persist классами       
  327.         case [| REF $name as $type |]:             
  328.                
  329.                 expander name.ToString(), 'int'
  330.  
  331.                 vars.Add(Field(Name: name_ref.ToString(), Type : type))
  332.                                
  333.                 type_ref = ReferenceExpression(type.ToString())
  334.                
  335.                 gtype = type as GenericTypeReference
  336.                 //контейнер или просто тип
  337.                 if gtype:                                                                              
  338.                     //все как раньше
  339.                     elem_type = ReferenceExpression(gtype.GenericArguments[0].ToString())
  340.                    
  341.                     container_type = ReferenceExpression(gtype.Name)                                           
  342.                                        
  343.                     result = [|                                                
  344.                    
  345.                         $name as $type:
  346.                             get:
  347.                                 if not $name_loaded:
  348.                                    
  349.                                     $name_loaded = true
  350.                                    
  351.                                     if exchange.$name:
  352.                                        
  353.                                         arr = datamap.load_arr[of int](exchange.$name)
  354.                                    
  355.                                         $name_ref = $container_type of $elem_type()
  356.                                        
  357.                                         for el_address in arr:
  358.                                            
  359.                                             if el_address:
  360.                                                
  361.                                                 el = $elem_type.load(datamap, el_address)
  362.                                             else:
  363.                                                 el = null
  364.                                            
  365.                                             $name_ref.Add(el)
  366.                                     else:
  367.                                         $name_ref = $container_type of $elem_type()
  368.                                        
  369.                                 return $name_ref   
  370.                             set:                                                                   
  371.                                 $name_ref = value
  372.                                
  373.                                 $name_loaded = true
  374.                                
  375.                                 arr_list = List of int()
  376.                                
  377.                                 for el in value:
  378.                                    
  379.                                     if el:
  380.                                    
  381.                                         if el.address == 0:
  382.                                            
  383.                                             el.save()
  384.                                            
  385.                                         addr = el.address
  386.                                     else:
  387.                                         addr = 0
  388.                                    
  389.                                     arr_list.Add(addr)
  390.                                
  391.                                 datamap.write_arr[of int](arr_list.ToArray(), exchange.$name)                  
  392.                     |]                 
  393.                 else: //для простого типа                     
  394.                     result = [|
  395.                        
  396.                         $name as $type:
  397.                             get:
  398.                                 if not $name_loaded:
  399.                        
  400.                                     $name_loaded = true
  401.                                        
  402.                                     $name_ref = $type_ref.load(datamap, exchange.$name) if exchange.$name
  403.                          
  404.                                 return $name_ref   
  405.                             set:                                                                   
  406.                                 $name_ref = value
  407.                                
  408.                                 $name_loaded = true
  409.                                
  410.                                 exchange.$name = $name_ref.address                 
  411.                    
  412.                     |]
  413.                    
  414.                 yield result
  415.  
  416.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement