Curl Global Community
Sonntag - proposed macro change - Printable Version

+- Curl Global Community (https://communities.curl.com)
+-- Forum: Blogs (https://communities.curl.com/forumdisplay.php?fid=17)
+--- Forum: Tech blog (https://communities.curl.com/forumdisplay.php?fid=18)
+---- Forum: Robert blog (https://communities.curl.com/forumdisplay.php?fid=20)
+---- Thread: Sonntag - proposed macro change (/showthread.php?tid=200)



Sonntag - proposed macro change - RobertShiplett - 08-11-2011

I have tested this alternative in a modified Sonntag-EventBus demo with pane and pane-container controls using both the identifier 'clear' and my preferred ScrnCommand.clear

Code:
{define-macro public
    {define-screen-command
        ?input-obj:expression
        of ?screen-spec:expression
        ?enabled:{optional {enabled? ?:statements}}
     do        
        ?execute-body:verbatim
    }
    let id:#Identifier = null
    let command-name:#Literal = null
    let str:String = "define-screen-command_unknown_token"  
    {syntax-switch
            input-obj,
            must-match? = true  
         case {pattern ?type:identifier} do
            set str = {String {input-obj.get-text}}
         case {pattern ?expr:statement} do
            {type-switch expr
             case bop:BinaryOp do
||              {output "BOP: " & bop}
||              let clss-name:String = "UnknownClass"
                {if (bop.operator == OperatorKind.Dot) then
||                  set clss-name = {String {bop.left.get-text}}  || test if class is kind of Command ?
                    set str = {String {bop.right.get-text}}
||                  {output "parsed Right: " & str}
                    {if str.empty? then                   || what else should we test ?
                        set str = "define-screen-command_parse-error"  || TODO set as a constant above
                    }
                 else
                    set str = "define-screen-command_invalid-op"  || TODO set as a constant above
                }
            }
     }
||    {if not {str.equal? "define-screen-command_unknown_token"} then {output input-obj}}
    set id = {Identifier str}   || what validation does this afford ?  id is not re-used    
    set command-name = {Literal id.name}
    || Screen class
    let screen-type:#CurlSource = null
    let screen-var-decl:#CurlSource = null
    {syntax-switch
        screen-spec,
        must-match? = true
     case {pattern ?type:identifier} do
        set screen-type = type
     case {pattern ?expr:expression} do
        let valid?:bool = false
        {type-switch expr
         case sb:SingleBinding do
            {if sb.value == null and sb.type != null then
                set screen-type = {non-null sb.type}
                set screen-var-decl =
                    {expand-template
                        let ?sb = self.screen
                    }
                set valid? = true
            }
        }
        {if not valid? then
            {expr.parse-error
                "Unexpected expression '%s'",
                {expr.get-text}
            }
        }
    }
    || Command class
    def command-class =
        {Identifier
            {screen-type.get-text} & '_' & command-name.value
        }
    || default constructor
    def constructor-src =
        {expand-template
            {constructor public {default screen:?screen-type}
                {construct-super ?command-name, screen}
            }
        }
    || enabled? getter
    def enabled-src =
        {syntax-switch
            enabled,
            must-match? = true
         case {pattern} do
            {EmptySource}
         case {pattern {enabled? ?enabled-body:statements}} do
            {expand-template
                {getter public {enabled?}:bool
                    ?screen-var-decl
                    {return {value ?enabled-body} and super.enabled?}
                }
            }
        }
    || execute method
    def execute-src =
        {expand-template
            {method public {execute}:void
                ?screen-var-decl
                ?execute-body
            }
        }
    {return
        {expand-template
            {define-class public ?=command-class
              {inherits {ScreenCommand-of ?screen-type}}
              ?constructor-src
              ?enabled-src
              ?execute-src
            }
            {do
                {ScreenCommandContext.registry.register-command
                    ?command-name, ?screen-type, ?command-class
                }
            }
        }
    }
}

The demo alternative for App.A is
Code:
|| Clear command for the content of ScreenA; note use of parameterized type
{define-screen-command
    ScrnCommand.clear of screen:AScreen  || this version uses a BinaryOp in the macro
do

and other changes are only self-documenting, such as in message-handler
Code:
{def clear-text-entry-field:String = ScrnCommand.clear}
    
    {if message == ScrnMsg.clear then
        {self.do-command clear-text-entry-field}
    }

Only define-screen-command.scurl is altered within the Sonntag framework itself.