Advertisement
Guest User

Untitled

a guest
Jun 11th, 2017
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
BOO 4.98 KB | None | 0 0
  1. namespace PersonTraits
  2.  
  3. import System
  4. import Boo.Lang
  5. import Boo.Lang.Compiler
  6. import Boo.Lang.Compiler.Ast
  7.  
  8. class Builder(AbstractAstAttribute):
  9.   entries as Hash
  10.   public def constructor(initString as StringLiteralExpression):
  11.     entries = Hash()
  12.     parts = /;/.Split(initString.Value)
  13.     for part in parts:
  14.       elements = /=/.Split(part)
  15.       props = /,/.Split(elements[1])
  16.       entries[elements[0]] = props
  17.  
  18.   public override def Apply(node as Node):
  19.     AddBuilderClass(node)
  20.     AddFactoryMethod(node)
  21.    
  22.   private def fieldName(propName as string) as string:
  23.     return char.ToLower(propName[0]) + propName.Substring(1)
  24.    
  25.   private def AddBuilderClass(node as ClassDefinition):
  26.     classRef = ReferenceExpression(node.Name)
  27.     fieldRef = ReferenceExpression(fieldName(node.Name))
  28.     builderRef = ReferenceExpression(node.Name + "Builder")
  29.     c = [|
  30.       class $(builderRef):
  31.         $(fieldRef) as $(classRef)
  32.         public def constructor($(fieldRef) as $(classRef)):
  33.           self.$(fieldRef) = $(fieldRef)
  34.         static def op_Implicit(o as $(builderRef)):
  35.           return o.$(fieldRef)
  36.     |]
  37.     AddIndividualFluentMethods(c, node)
  38.     AddCombinationFluentMethods(c, node)
  39.     AddInternalBuilders(c, node)
  40.     (node.ParentNode as Module).Members.Add(c)
  41.  
  42.   private def AddInternalBuilders(builder as ClassDefinition, source as ClassDefinition):
  43.     // iterate over each set
  44.     for entry in entries:
  45.       // create and a stub class
  46.       classRef = ReferenceExpression(source.Name + entry.Key + "Builder")
  47.       targetRef = ReferenceExpression(source.Name)
  48.       outerFieldRef = ReferenceExpression(fieldName(source.Name))
  49.       innerClass = [|
  50.         class $classRef:
  51.           $outerFieldRef as $targetRef
  52.           public def constructor($(outerFieldRef) as $targetRef):
  53.             self.$(outerFieldRef) = $(outerFieldRef)
  54.           static def op_Implicit(o as $builder):
  55.             return o.$(outerFieldRef)
  56.       |]
  57.       // spawn each setter for this class
  58.       for prop in entry.Value:
  59.         for sp in source.Members:
  60.           p2 = sp as Property
  61.           if p2 != null and prop == p2.Name:
  62.             methodRef = ReferenceExpression("With" + prop)
  63.             fieldRef = ReferenceExpression(fieldName(prop))
  64.             propRef = ReferenceExpression(prop as string)
  65.             // let's do it
  66.             setter = [|
  67.               public def $methodRef($fieldRef as $(p2.Type)) as $classRef:
  68.                 $outerFieldRef.$propRef = $fieldRef
  69.                 return self
  70.             |]
  71.             innerClass.Members.Add(setter)
  72.       // ensure a property exists for this class in the root builder
  73.       prop = [|
  74.         public $(ReferenceExpression(entry.Key as string)):
  75.           get:
  76.             return $classRef($(ReferenceExpression(fieldName(source.Name))))
  77.       |]
  78.       builder.Members.Add(prop)
  79.       // ensure inner builders expose divergent properties
  80.       for entry2 in entries:
  81.         if entry.Key != entry2.Key:
  82.           otherClassRef = ReferenceExpression(source.Name + entry2.Key + "Builder")
  83.           prop = [|
  84.             public $(ReferenceExpression(entry2.Key as string)):
  85.               get:
  86.                 return $otherClassRef($outerFieldRef)
  87.           |]
  88.           innerClass.Members.Add(prop)
  89.       // add it all
  90.       builder.Members.Add(innerClass)
  91.  
  92.   private def AddCombinationFluentMethods(builder as ClassDefinition, source as ClassDefinition):
  93.     for entry in entries:
  94.       m = Method("With" + entry.Key)
  95.       for p in entry.Value as (string):
  96.         // look for this param in the class
  97.         for sp in source.Members:
  98.           prop = sp as Property
  99.           if prop != null and p == prop.Name:
  100.             mp = ParameterDeclaration(fieldName(prop.Name), prop.Type)
  101.             m.Parameters.Add(mp)
  102.             sourceRef = ReferenceExpression(fieldName(source.Name))
  103.             propRef = ReferenceExpression(prop.Name)
  104.             a = [|
  105.               $sourceRef.$propRef = $mp
  106.             |]
  107.             m.Body.Add(a)
  108.       m.Body.Statements.Add([| return self |])
  109.       builder.Members.Add(m)
  110.  
  111.   private def AddIndividualFluentMethods(builder as ClassDefinition, source as ClassDefinition):
  112.     builderRef = ReferenceExpression(builder.Name)
  113.     for prop in source.Members:
  114.       p = prop as Property
  115.       if p != null:
  116.         methodName = ReferenceExpression("With" + p.Name)
  117.         propRef = ReferenceExpression(p.Name)
  118.         paramRef = ReferenceExpression(fieldName(p.Name))
  119.         m = [|
  120.           public def $(methodName)($paramRef as $(p.Type)) as $(builderRef):
  121.             person.$(propRef) = $paramRef
  122.             return self
  123.         |]
  124.         builder.Members.Add(m)
  125.  
  126.   private def AddFactoryMethod(node as ClassDefinition):
  127.     builderRef = ReferenceExpression(node.Name + "Builder")
  128.     classRef = ReferenceExpression(node.Name)
  129.     m = [|
  130.       def Create() as $(builderRef):
  131.         return $(builderRef)($(classRef)())
  132.     |]
  133.     node.Members.Add(m)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement