Automatic editor node type inference for string literal/string expression

(Apologies if this is an easy one, and also please let me know if there's a better way to do what I'm trying to do.)

I'm building a DSL in which one of my concepts (call it MyFunction) has a child that must either be a string literal or a concept that ultimately resolves to a string.  I've set up a simple concept hierarchy like this:

AbstractStringExpression
-- StringLiteralExpression (has property "value" of type string)
-- AFunctionThatReturnsString
-- AnotherFunctionThatReturnsString

And I've got the aforementioned original concept, MyFunction, has a child called value of type AbstractStringExpression (cardinality 1).

What I'm having trouble accomplishing is this: when the user is entering the "value" child of MyFunction, I'd like to have the editor infer that the value the user is entering is a string literal, either by the user starting out by typing double-quotes, or once the text the user enters clearly doesn't match the alias of any concept that descends from AbstractStringExpression, and subsequently automatically substitute a StringLiteralExpression node for the initially null AbstractStringExpression node.

I see that the "expressions" sample that ships with MPS does this for the initializer in variable declarations; the initial node is of concept Expression, but once you type a non-zero number it is automatically substituted to IntegerConstant, and if you subsequently enter a decimal, it is again substituted to FlatConstant.  So I know that theoretically this type of inference and node substitution based on the user's input is possible, but I just can't seem to figure out how it is done.

Any input you can give me would be greatly appreciated.

Thanks,
Scott
1 comment
This is definitely a non-trivial editing question.
I suggest that you create a node substitution action as follows:

node substitute actions <no name>        
           
substituted node: AbstractStringExpression  // <no description>        
  condition :             
    <none> 
           
  common initializer :    
    <no common variables> 
    .................................... 
     <no supplemental initializer>       
           
  actions :
    remove defaults       
    ----------            
    add custom items  (output concept: StringLiteralExpression)        
      simple item         
        can substitute    
          <default>       
        matching text     
          "
        description text  
          <default>       
        icon node         
          <default>       
        type              
          <default>       
        create child node 
          (pattern, parentNode, currentTargetNode, childConcept, model, operationContext)->node<StringLiteralExpression> { 
  currentTargetNode.replace with new initialized(StringLiteralExpression); 
}     
        selection handler 
          <default>       
           
    ----------            
    add custom items  (output concept: StringLiteralExpression)        
      simple item         
        can substitute    
          (pattern, strictly, parentNode, currentTargetNode, childConcept, model, operationContext)->boolean { 
  pattern.isNotEmpty && pattern :ne: "afunc" && pattern :ne: "\""; 
}          
        matching text     
          <default>       
        description text  
          <default>       
        icon node         
          <default>       
        type              
          <default>       
        create child node 
          (pattern, parentNode, currentTargetNode, childConcept, model, operationContext)->node<StringLiteralExpression> { 
  node<StringLiteralExpression> newNode = currentTargetNode.replace with new initialized(StringLiteralExpression); 
  newNode.value = pattern; 
  newNode; 
}
        selection handler 
          <default>       
           
    ----------            
    add custom items  (output concept: AFunctionThatReturnsString)     
      simple item         
        can substitute    
          <default>       
        matching text     
          afunc           
        description text  
          <default>       
        icon node         
          <default>       
        type              
          <default>       
        create child node 
          (pattern, parentNode, currentTargetNode, childConcept, model, operationContext)->node<AFunctionThatReturnsString> { 
  currentTargetNode.replace with new initialized(AFunctionThatReturnsString); 
}              
        selection handler 
          <default>       
           
prettyPrint();
0

Please sign in to leave a comment.