1// ================================================================ 2// This is for things that get us out of statement blocks: break, continue, 3// return. 4// ================================================================ 5 6package cst 7 8import ( 9 "errors" 10 11 "miller/src/dsl" 12 "miller/src/lib" 13 "miller/src/runtime" 14) 15 16// ---------------------------------------------------------------- 17type BreakNode struct { 18} 19 20func (this *RootNode) BuildBreakNode(astNode *dsl.ASTNode) (*BreakNode, error) { 21 lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeBreak) 22 lib.InternalCodingErrorIf(astNode.Children == nil) 23 lib.InternalCodingErrorIf(len(astNode.Children) != 0) 24 25 return &BreakNode{}, nil 26} 27 28func (this *BreakNode) Execute(state *runtime.State) (*BlockExitPayload, error) { 29 return &BlockExitPayload{ 30 BLOCK_EXIT_BREAK, 31 nil, 32 }, nil 33} 34 35// ---------------------------------------------------------------- 36type ContinueNode struct { 37} 38 39func (this *RootNode) BuildContinueNode(astNode *dsl.ASTNode) (*ContinueNode, error) { 40 lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeContinue) 41 lib.InternalCodingErrorIf(astNode.Children == nil) 42 lib.InternalCodingErrorIf(len(astNode.Children) != 0) 43 44 return &ContinueNode{}, nil 45} 46 47func (this *ContinueNode) Execute(state *runtime.State) (*BlockExitPayload, error) { 48 return &BlockExitPayload{ 49 BLOCK_EXIT_CONTINUE, 50 nil, 51 }, nil 52} 53 54// ---------------------------------------------------------------- 55type ReturnNode struct { 56 returnValueExpression IEvaluable 57} 58 59func (this *RootNode) BuildReturnNode(astNode *dsl.ASTNode) (*ReturnNode, error) { 60 lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeReturn) 61 lib.InternalCodingErrorIf(astNode.Children == nil) 62 if len(astNode.Children) == 0 { 63 return &ReturnNode{returnValueExpression: nil}, nil 64 } else if len(astNode.Children) == 1 { 65 returnValueExpression, err := this.BuildEvaluableNode(astNode.Children[0]) 66 if err != nil { 67 return nil, err 68 } 69 return &ReturnNode{returnValueExpression: returnValueExpression}, nil 70 } else { 71 lib.InternalCodingErrorIf(true) 72 } 73 return nil, errors.New("Internal coding error: Statement should not be reached.") 74} 75 76func (this *ReturnNode) Execute(state *runtime.State) (*BlockExitPayload, error) { 77 if this.returnValueExpression == nil { 78 return &BlockExitPayload{ 79 BLOCK_EXIT_RETURN_VOID, 80 nil, 81 }, nil 82 } else { 83 // The return value can be of type MT_ERROR but we do not use Go-level error return here. 84 returnValue := this.returnValueExpression.Evaluate(state) 85 return &BlockExitPayload{ 86 BLOCK_EXIT_RETURN_VALUE, 87 returnValue.Copy(), 88 }, nil 89 } 90} 91