for/while loops

This commit is contained in:
John Kerl 2020-09-23 00:41:22 -04:00
parent 775e9bbaa2
commit 2caed6c01c
26 changed files with 309590 additions and 292678 deletions

2
go/.gitignore vendored
View file

@ -4,3 +4,5 @@ bin/
*.ast
mkv.ast
s
mlrgo
gg

View file

@ -47,11 +47,14 @@ const (
NodeTypeOperator = "Operator"
NodeTypeFunctionCallsite = "FunctionCallsite"
NodeTypeBeginBlock = "BeginBlock"
NodeTypeEndBlock = "EndBlock"
NodeTypeIfChain = "IfChain"
NodeTypeIfItem = "IfItem"
NodeTypeForLoopKeyOnly = "ForLoopKeyOnly"
NodeTypeBeginBlock = "BeginBlock"
NodeTypeEndBlock = "EndBlock"
NodeTypeIfChain = "IfChain"
NodeTypeIfItem = "IfItem"
NodeTypeWhileLoop = "WhileLoop"
NodeTypeDoWhileLoop = "DoWhileLoop"
NodeTypeForLoopKeyOnly = "ForLoopKeyOnly"
NodeTypeForLoopKeyValue = "ForLoopKeyValue"
// A special token which causes a panic when evaluated. This is for
// testing that AND/OR short-circuiting is implemented correctly: output =
@ -240,7 +243,9 @@ func NewASTNodeBinaryNestable(itok, childA, childB interface{}, nodeType TNodeTy
}
// Signature: Token Node Node Type
func NewASTNodeBinary(itok, childA, childB interface{}, nodeType TNodeType) (*ASTNode, error) {
func NewASTNodeBinary(
itok, childA, childB interface{}, nodeType TNodeType,
) (*ASTNode, error) {
return NewASTNodeBinaryNestable(itok, childA, childB, nodeType), nil
}
@ -250,6 +255,14 @@ func NewASTNodeTernary(itok, childA, childB, childC interface{}, nodeType TNodeT
return parent, nil
}
func NewASTNodeQuaternary(
itok, childA, childB, childC, childD interface{}, nodeType TNodeType,
) (*ASTNode, error) {
parent := NewASTNodeNestable(itok, nodeType)
convertToQuaternary(parent, childA, childB, childC, childD)
return parent, nil
}
// Pass-through expressions in the grammar sometimes need to be turned from
// (ASTNode) to (ASTNode, error)
func Nestable(iparent interface{}) (*ASTNode, error) {
@ -287,6 +300,16 @@ func convertToTernary(iparent interface{}, childA, childB, childC interface{}) {
parent.Children = children
}
func convertToQuaternary(iparent interface{}, childA, childB, childC, childD interface{}) {
parent := iparent.(*ASTNode)
children := make([]*ASTNode, 4)
children[0] = childA.(*ASTNode)
children[1] = childB.(*ASTNode)
children[2] = childC.(*ASTNode)
children[3] = childD.(*ASTNode)
parent.Children = children
}
func PrependChild(iparent interface{}, ichild interface{}) (*ASTNode, error) {
parent := iparent.(*ASTNode)
child := ichild.(*ASTNode)
@ -316,6 +339,12 @@ func AdoptChildren(iparent interface{}, ichild interface{}) (*ASTNode, error) {
return parent, nil
}
// TODO: comment
func Wrap(inode interface{}) (*ASTNode, error) {
node := inode.(*ASTNode)
return node, nil
}
func (this *ASTNode) CheckArity(
arity int,
) error {

View file

@ -89,6 +89,8 @@ func BuildStatementBlockNode(astNode *dsl.ASTNode) (*StatementBlockNode, error)
// ----------------------------------------------------------------
func (this *StatementBlockNode) Execute(state *State) error {
state.stack.PushStackFrame()
defer state.stack.PopStackFrame()
for _, statement := range this.executables {
err := statement.Execute(state)

View file

@ -1,31 +1,40 @@
package cst
import (
//"errors"
"errors"
"miller/dsl"
"miller/lib"
//"miller/types"
"miller/types"
)
// ================================================================
// This is for various flavors of for-loop
// ================================================================
// ----------------------------------------------------------------
// ================================================================
type ForLoopKeyOnlyNode struct {
keyVariableName string
mapNode IEvaluable
statementBlockNode *StatementBlockNode
}
func NewForLoopKeyOnlyNode(
keyVariableName string,
mapNode IEvaluable,
statementBlockNode *StatementBlockNode,
) *ForLoopKeyOnlyNode {
return &ForLoopKeyOnlyNode{
keyVariableName,
mapNode,
statementBlockNode,
}
}
// ----------------------------------------------------------------
// Sample AST:
// mlr -n put -v for (k in $*) { emit { k : k} }
// mlr -n put -v 'for (k in $*) { emit { k : k } }'
// DSL EXPRESSION:
// for (k in $*) { emit { k : k} }
// RAW AST:
@ -42,11 +51,190 @@ func NewForLoopKeyOnlyNode(
func BuildForLoopKeyOnlyNode(astNode *dsl.ASTNode) (*ForLoopKeyOnlyNode, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeForLoopKeyOnly)
lib.InternalCodingErrorIf(len(astNode.Children) != 3)
return NewForLoopKeyOnlyNode(), nil
keyVariableASTNode := astNode.Children[0]
mapASTNode := astNode.Children[1]
blockASTNode := astNode.Children[2]
lib.InternalCodingErrorIf(keyVariableASTNode.Type != dsl.NodeTypeLocalVariable)
lib.InternalCodingErrorIf(keyVariableASTNode.Token == nil)
keyVariableName := string(keyVariableASTNode.Token.Lit)
// TODO: error if loop-over node isn't Mappable (inasmuch as can be
// detected at CST-build time)
mapNode, err := BuildEvaluableNode(mapASTNode)
if err != nil {
return nil, err
}
statementBlockNode, err := BuildStatementBlockNode(blockASTNode)
if err != nil {
return nil, err
}
return NewForLoopKeyOnlyNode(
keyVariableName,
mapNode,
statementBlockNode,
), nil
}
// ----------------------------------------------------------------
func (this *ForLoopKeyOnlyNode) Execute(state *State) error {
mlrval := this.mapNode.Evaluate(state)
if !mlrval.IsMap() {
// TODO: more
return errors.New("Miller: looped-over item is not a map.")
}
mapval := mlrval.GetMap()
state.stack.PushStackFrame()
defer state.stack.PopStackFrame()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(*pe.Key)
// Note: The statement-block has its own push/pop for its localvars.
// Meanwhile we need to restrict scope of the bindvar to the for-loop.
//
// So we have:
//
// mlr put '
// x = 1; <--- frame #1 main
// for (k in $*) { <--- frame #2 for for-loop bindvars (right here)
// x = 2 <--- frame #3 for for-loop locals
// }
// x = 3; <--- back in frame #1 main
// '
//
state.stack.BindVariable(this.keyVariableName, &mapkey)
//state.stack.Dump()
err := this.statementBlockNode.Execute(state)
if err != nil {
return err
}
}
return nil
}
// ================================================================
type ForLoopKeyValueNode struct {
keyVariableName string
valueVariableName string
mapNode IEvaluable
statementBlockNode *StatementBlockNode
}
func NewForLoopKeyValueNode(
keyVariableName string,
valueVariableName string,
mapNode IEvaluable,
statementBlockNode *StatementBlockNode,
) *ForLoopKeyValueNode {
return &ForLoopKeyValueNode{
keyVariableName,
valueVariableName,
mapNode,
statementBlockNode,
}
}
// ----------------------------------------------------------------
// Sample AST:
// mlr -n put -v 'for (k, v in $*) { emit { k : v } }'
// DSL EXPRESSION:
// for (k, v in $*) { emit { k : v } }
// RAW AST:
// * StatementBlock
// * ForLoopKeyValue "for"
// * LocalVariable "k"
// * LocalVariable "v"
// * FullSrec "$*"
// * StatementBlock
// * EmitStatement "emit"
// * MapLiteral "{}"
// * MapLiteralKeyValuePair ":"
// * LocalVariable "k"
// * LocalVariable "v"
func BuildForLoopKeyValueNode(astNode *dsl.ASTNode) (*ForLoopKeyValueNode, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeForLoopKeyValue)
lib.InternalCodingErrorIf(len(astNode.Children) != 4)
keyVariableASTNode := astNode.Children[0]
valueVariableASTNode := astNode.Children[1]
mapASTNode := astNode.Children[2]
blockASTNode := astNode.Children[3]
lib.InternalCodingErrorIf(keyVariableASTNode.Type != dsl.NodeTypeLocalVariable)
lib.InternalCodingErrorIf(keyVariableASTNode.Token == nil)
keyVariableName := string(keyVariableASTNode.Token.Lit)
lib.InternalCodingErrorIf(valueVariableASTNode.Type != dsl.NodeTypeLocalVariable)
lib.InternalCodingErrorIf(valueVariableASTNode.Token == nil)
valueVariableName := string(valueVariableASTNode.Token.Lit)
// TODO: error if loop-over node isn't Mappable (inasmuch as can be
// detected at CST-build time)
mapNode, err := BuildEvaluableNode(mapASTNode)
if err != nil {
return nil, err
}
statementBlockNode, err := BuildStatementBlockNode(blockASTNode)
if err != nil {
return nil, err
}
return NewForLoopKeyValueNode(
keyVariableName,
valueVariableName,
mapNode,
statementBlockNode,
), nil
}
// ----------------------------------------------------------------
func (this *ForLoopKeyValueNode) Execute(state *State) error {
mlrval := this.mapNode.Evaluate(state)
if !mlrval.IsMap() {
// TODO: more
return errors.New("Miller: looped-over item is not a map.")
}
mapval := mlrval.GetMap()
state.stack.PushStackFrame()
defer state.stack.PopStackFrame()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(*pe.Key)
// Note: The statement-block has its own push/pop for its localvars.
// Meanwhile we need to restrict scope of the bindvar to the for-loop.
//
// So we have:
//
// mlr put '
// x = 1; <--- frame #1 main
// for (k in $*) { <--- frame #2 for for-loop bindvars (right here)
// x = 2 <--- frame #3 for for-loop locals
// }
// x = 3; <--- back in frame #1 main
// '
//
state.stack.BindVariable(this.keyVariableName, &mapkey)
state.stack.BindVariable(this.valueVariableName, pe.Value)
//state.stack.Dump()
err := this.statementBlockNode.Execute(state)
if err != nil {
return err
}
}
return nil
}

View file

@ -325,7 +325,7 @@ var BUILTIN_FUNCTION_LOOKUP_TABLE = []FunctionInfo{
name: "urandrange",
},
{
name: "truncate",
name: "truncate",
binaryFunc: types.MlrvalTruncate,
},

View file

@ -36,6 +36,10 @@ func BuildLeafNode(
return BuildFullOosvarRvalueNode(sval), nil
break
case dsl.NodeTypeLocalVariable:
return BuildLocalVariableNode(sval), nil
break
case dsl.NodeTypeStringLiteral:
return BuildStringLiteralNode(sval), nil
break
@ -125,6 +129,26 @@ func (this *FullOosvarRvalueNode) Evaluate(state *State) types.Mlrval {
return types.MlrvalFromMap(state.Oosvars)
}
// ----------------------------------------------------------------
type LocalVariableNode struct {
variableName string
}
func BuildLocalVariableNode(variableName string) *LocalVariableNode {
return &LocalVariableNode{
variableName: variableName,
}
}
func (this *LocalVariableNode) Evaluate(state *State) types.Mlrval {
value := state.stack.ReadVariable(this.variableName)
//state.stack.Dump()
if value == nil {
return types.MlrvalFromAbsent()
} else {
return *value
}
}
// ----------------------------------------------------------------
type StringLiteralNode struct {
literal types.Mlrval

View file

@ -0,0 +1,88 @@
package cst
import (
"container/list"
"fmt"
"miller/types"
)
// ================================================================
// Stack frames for begin/end/if/for/function blocks
// ================================================================
// ----------------------------------------------------------------
type Stack struct {
stackFrames *list.List // list of *StackFrame
}
func NewStack() *Stack {
return &Stack {
stackFrames: list.New(),
}
}
func (this *Stack) PushStackFrame() {
this.stackFrames.PushFront(NewStackFrame())
}
func (this *Stack) PopStackFrame() {
this.stackFrames.Remove(this.stackFrames.Front())
}
func (this *Stack) BindVariable(name string, mlrval *types.Mlrval) {
this.stackFrames.Front().Value.(*StackFrame).Bind(name, mlrval)
}
// Returns nil on no-such
func (this *Stack) ReadVariable(name string) *types.Mlrval {
// Scope-walk
for entry := this.stackFrames.Front(); entry != nil; entry = entry.Next() {
stackFrame := entry.Value.(*StackFrame)
mlrval := stackFrame.ReadVariable(name)
if mlrval != nil {
return mlrval
}
}
return nil
}
// Returns nil on no-such
func (this *Stack) Dump() {
fmt.Printf("STACK FRAMES (count %d):\n", this.stackFrames.Len())
for entry := this.stackFrames.Front(); entry != nil; entry = entry.Next() {
stackFrame := entry.Value.(*StackFrame)
fmt.Printf(" VARIABLES (count %d):\n", len(stackFrame.vars))
for k, v := range(stackFrame.vars) {
fmt.Printf(" %-16s %s\n", k, v.String())
}
}
}
// ----------------------------------------------------------------
type StackFrame struct {
// TODO: just a map for now. In the C impl, pre-computation of
// name-to-array-slot indices was an important optimization, especially for
// compute-intensive scenarios.
vars map[string]*types.Mlrval
}
func NewStackFrame() *StackFrame {
return &StackFrame{
vars: make(map[string]*types.Mlrval),
}
}
func (this *StackFrame) Clear() {
this.vars = make(map[string]*types.Mlrval)
}
func (this *StackFrame) Bind(name string, mlrval *types.Mlrval) {
this.vars[name] = mlrval.Copy()
}
// Returns nil on no such
func (this *StackFrame) ReadVariable(name string) *types.Mlrval {
return this.vars[name]
}

View file

@ -0,0 +1,25 @@
package cst
import (
"miller/types"
)
func NewEmptyState() *State {
oosvars := types.NewMlrmap()
return &State{
Inrec: nil,
Context: nil,
Oosvars: oosvars,
FilterResult: true,
// OutputChannel is assigned after construction
stack: NewStack(),
}
}
func (this *State) Update(
inrec *types.Mlrmap,
context *types.Context,
) {
this.Inrec = inrec
this.Context = context
}

View file

@ -46,8 +46,14 @@ func BuildStatementNode(
case dsl.NodeTypeIfChain:
return BuildIfChainNode(astNode)
case dsl.NodeTypeWhileLoop:
return BuildWhileLoopNode(astNode)
case dsl.NodeTypeDoWhileLoop:
return BuildDoWhileLoopNode(astNode)
case dsl.NodeTypeForLoopKeyOnly:
return BuildForLoopKeyOnlyNode(astNode)
case dsl.NodeTypeForLoopKeyValue:
return BuildForLoopKeyValueNode(astNode)
default:
return nil, errors.New(

View file

@ -32,33 +32,11 @@ type State struct {
Oosvars *types.Mlrmap
FilterResult bool
OutputChannel chan<- *types.RecordAndContext
// TODO: stack frames will go into individual statement-block nodes or here?
// Needs to be here, for scope-resolution walks
}
func NewEmptyState() *State {
oosvars := types.NewMlrmap()
return &State{
Inrec: nil,
Context: nil,
Oosvars: oosvars,
FilterResult: true,
}
}
func (this *State) Update(
inrec *types.Mlrmap,
context *types.Context,
) {
this.Inrec = inrec
this.Context = context
stack *Stack
}
// ----------------------------------------------------------------
type RootNode struct {
// TODO: Statements/blocks
//executables []IExecutable
beginBlocks []*StatementBlockNode
mainBlock *StatementBlockNode
endBlocks []*StatementBlockNode
@ -79,7 +57,6 @@ type IExecutable interface {
// Also implements IExecutable
type StatementBlockNode struct {
executables []IExecutable
// TODO: localvars -- here or in State's stack-frame
}
// ================================================================

View file

@ -0,0 +1,123 @@
package cst
import (
"errors"
"miller/dsl"
"miller/lib"
)
// ================================================================
// This is for while/do-while loops
// ================================================================
// ================================================================
type WhileLoopNode struct {
conditionNode IEvaluable
statementBlockNode *StatementBlockNode
}
func NewWhileLoopNode(
conditionNode IEvaluable,
statementBlockNode *StatementBlockNode,
) *WhileLoopNode {
return &WhileLoopNode{
conditionNode: conditionNode,
statementBlockNode: statementBlockNode,
}
}
func BuildWhileLoopNode(astNode *dsl.ASTNode) (*WhileLoopNode, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeWhileLoop)
lib.InternalCodingErrorIf(len(astNode.Children) != 2)
conditionNode, err := BuildEvaluableNode(astNode.Children[0])
if err != nil {
return nil, err
}
statementBlockNode, err := BuildStatementBlockNode(astNode.Children[1])
if err != nil {
return nil, err
}
return NewWhileLoopNode(
conditionNode,
statementBlockNode,
), nil
}
// ----------------------------------------------------------------
func (this *WhileLoopNode) Execute(state *State) error {
for {
condition := this.conditionNode.Evaluate(state)
boolValue, isBool := condition.GetBoolValue()
if !isBool {
// TODO: line-number/token info for the DSL expression.
return errors.New("Miller: conditional expression did not evaluate to boolean.")
}
if boolValue != true {
break
}
err := this.statementBlockNode.Execute(state)
if err != nil {
return err
}
}
return nil
}
// ================================================================
type DoWhileLoopNode struct {
statementBlockNode *StatementBlockNode
conditionNode IEvaluable
}
func NewDoWhileLoopNode(
statementBlockNode *StatementBlockNode,
conditionNode IEvaluable,
) *DoWhileLoopNode {
return &DoWhileLoopNode{
statementBlockNode: statementBlockNode,
conditionNode: conditionNode,
}
}
func BuildDoWhileLoopNode(astNode *dsl.ASTNode) (*DoWhileLoopNode, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeDoWhileLoop)
lib.InternalCodingErrorIf(len(astNode.Children) != 2)
statementBlockNode, err := BuildStatementBlockNode(astNode.Children[0])
if err != nil {
return nil, err
}
conditionNode, err := BuildEvaluableNode(astNode.Children[1])
if err != nil {
return nil, err
}
return NewDoWhileLoopNode(
statementBlockNode,
conditionNode,
), nil
}
// ----------------------------------------------------------------
func (this *DoWhileLoopNode) Execute(state *State) error {
for {
err := this.statementBlockNode.Execute(state)
if err != nil {
return err
}
condition := this.conditionNode.Evaluate(state)
boolValue, isBool := condition.GetBoolValue()
if !isBool {
// TODO: line-number/token info for the DSL expression.
return errors.New("Miller: conditional expression did not evaluate to boolean.")
}
if boolValue == false {
break
}
}
return nil
}

View file

@ -88,9 +88,9 @@ being 'b=3,c=4', then the output is the two records 'a=1,b=2,c=' and
// ----------------------------------------------------------------
type MapperUnsparsify struct {
fillerString string
fillerString string
recordsAndContexts *list.List
fieldNamesSeen *lib.OrderedMap
fieldNamesSeen *lib.OrderedMap
}
func NewMapperUnsparsify(
@ -98,9 +98,9 @@ func NewMapperUnsparsify(
) (*MapperUnsparsify, error) {
this := &MapperUnsparsify{
fillerString: fillerString,
fillerString: fillerString,
recordsAndContexts: list.New(),
fieldNamesSeen: lib.NewOrderedMap(),
fieldNamesSeen: lib.NewOrderedMap(),
}
return this, nil

File diff suppressed because it is too large Load diff

View file

@ -11,8 +11,8 @@ import (
const (
NoState = -1
NumStates = 211
NumSymbols = 344
NumStates = 217
NumSymbols = 351
)
type Lexer struct {
@ -179,282 +179,289 @@ Lexer symbols:
63: 'g'
64: 'i'
65: 'n'
66: 'e'
67: 'n'
66: 'd'
67: 'o'
68: 'd'
69: 'f'
70: 'i'
71: 'l'
72: 't'
73: 'e'
74: 'r'
75: 'e'
76: 'm'
77: 'i'
78: 't'
79: 'd'
80: 'u'
81: 'm'
82: 'p'
83: 'e'
84: 'd'
85: 'u'
69: 'u'
70: 'm'
71: 'p'
72: 'e'
73: 'd'
74: 'u'
75: 'm'
76: 'p'
77: 'e'
78: 'l'
79: 'i'
80: 'f'
81: 'e'
82: 'l'
83: 's'
84: 'e'
85: 'e'
86: 'm'
87: 'p'
88: 'i'
89: 'f'
90: 'e'
91: 'l'
92: 'i'
93: 'f'
94: 'e'
95: 'l'
96: 's'
97: 'e'
87: 'i'
88: 't'
89: 'e'
90: 'n'
91: 'd'
92: 'f'
93: 'i'
94: 'l'
95: 't'
96: 'e'
97: 'r'
98: 'f'
99: 'o'
100: 'r'
101: 'i'
102: 'n'
102: 'f'
103: 'i'
104: 'n'
105: 't'
106: 'f'
107: 'l'
108: 'o'
109: 'a'
110: 't'
111: '$'
112: '$'
113: '{'
114: '}'
115: '$'
116: '*'
117: '@'
118: '@'
119: '{'
120: '}'
121: '@'
122: '*'
123: '%'
124: '%'
125: '%'
126: 'p'
127: 'a'
128: 'n'
129: 'i'
130: 'c'
105: 'w'
106: 'h'
107: 'i'
108: 'l'
109: 'e'
110: 'i'
111: 'n'
112: 't'
113: 'f'
114: 'l'
115: 'o'
116: 'a'
117: 't'
118: '$'
119: '$'
120: '{'
121: '}'
122: '$'
123: '*'
124: '@'
125: '@'
126: '{'
127: '}'
128: '@'
129: '*'
130: '%'
131: '%'
132: '%'
133: '%'
134: ';'
135: '='
136: '$'
137: '['
138: ']'
139: '@'
140: '['
141: '|'
142: '|'
143: '='
144: '^'
145: '^'
146: '='
147: '&'
148: '&'
149: '='
133: 'p'
134: 'a'
135: 'n'
136: 'i'
137: 'c'
138: '%'
139: '%'
140: '%'
141: ';'
142: '{'
143: '}'
144: '='
145: '$'
146: '['
147: ']'
148: '@'
149: '['
150: '|'
151: '='
152: '^'
153: '='
154: '<'
155: '<'
156: '='
157: '>'
158: '>'
159: '='
160: '>'
161: '>'
162: '>'
163: '='
164: '+'
151: '|'
152: '='
153: '^'
154: '^'
155: '='
156: '&'
157: '&'
158: '='
159: '|'
160: '='
161: '^'
162: '='
163: '<'
164: '<'
165: '='
166: '.'
167: '='
168: '-'
169: '='
170: '*'
171: '='
172: '/'
173: '='
174: '/'
175: '/'
166: '>'
167: '>'
168: '='
169: '>'
170: '>'
171: '>'
172: '='
173: '+'
174: '='
175: '.'
176: '='
177: '%'
177: '-'
178: '='
179: '*'
180: '*'
181: '='
182: '?'
183: ':'
184: '|'
185: '|'
186: '^'
187: '^'
188: '&'
189: '&'
180: '='
181: '/'
182: '='
183: '/'
184: '/'
185: '='
186: '%'
187: '='
188: '*'
189: '*'
190: '='
191: '~'
192: '!'
193: '='
194: '~'
195: '='
196: '='
197: '!'
198: '='
199: '>'
200: '>'
201: '='
202: '<'
203: '<'
191: '?'
192: ':'
193: '|'
194: '|'
195: '^'
196: '^'
197: '&'
198: '&'
199: '='
200: '~'
201: '!'
202: '='
203: '~'
204: '='
205: '|'
206: '^'
207: '&'
208: '<'
209: '<'
210: '>'
211: '>'
212: '>'
213: '>'
214: '>'
215: '+'
216: '-'
217: '.'
218: '+'
219: '.'
220: '-'
221: '.'
222: '*'
223: '/'
224: '/'
225: '/'
226: '%'
227: '.'
228: '*'
229: '.'
230: '/'
231: '.'
205: '='
206: '!'
207: '='
208: '>'
209: '>'
210: '='
211: '<'
212: '<'
213: '='
214: '|'
215: '^'
216: '&'
217: '<'
218: '<'
219: '>'
220: '>'
221: '>'
222: '>'
223: '>'
224: '+'
225: '-'
226: '.'
227: '+'
228: '.'
229: '-'
230: '.'
231: '*'
232: '/'
233: '/'
234: '!'
235: '~'
236: '*'
234: '/'
235: '%'
236: '.'
237: '*'
238: '('
239: ')'
240: '['
241: ','
242: '{'
243: '}'
244: '_'
245: ' '
246: '!'
247: '#'
248: '$'
249: '%'
250: '&'
251: '''
252: '\'
253: '('
254: ')'
255: '*'
256: '+'
257: ','
258: '-'
259: '.'
260: '/'
261: ':'
262: ';'
263: '<'
264: '='
265: '>'
266: '?'
267: '@'
268: '['
269: ']'
270: '^'
271: '_'
272: '`'
273: '{'
274: '|'
275: '}'
276: '~'
277: '\'
278: '"'
279: 'e'
280: 'E'
281: 't'
282: 'r'
283: 'u'
284: 'e'
285: 'f'
286: 'a'
287: 'l'
288: 's'
289: 'e'
290: ' '
291: '!'
292: '#'
293: '$'
294: '%'
295: '&'
296: '''
297: '\'
298: '('
299: ')'
300: '*'
301: '+'
302: ','
303: '-'
304: '.'
305: '/'
306: ':'
307: ';'
308: '<'
309: '='
310: '>'
311: '?'
312: '@'
313: '['
314: ']'
315: '^'
316: '_'
317: '`'
318: '|'
319: '~'
320: '\'
321: '{'
322: '\'
323: '}'
324: ' '
325: '\t'
326: '\n'
327: '\r'
328: 'a'-'z'
329: 'A'-'Z'
330: '0'-'9'
331: '0'-'9'
332: 'a'-'f'
333: 'A'-'F'
334: '0'-'1'
335: 'A'-'Z'
336: 'a'-'z'
238: '.'
239: '/'
240: '.'
241: '/'
242: '/'
243: '!'
244: '~'
245: '*'
246: '*'
247: '('
248: ')'
249: '['
250: ','
251: '_'
252: ' '
253: '!'
254: '#'
255: '$'
256: '%'
257: '&'
258: '''
259: '\'
260: '('
261: ')'
262: '*'
263: '+'
264: ','
265: '-'
266: '.'
267: '/'
268: ':'
269: ';'
270: '<'
271: '='
272: '>'
273: '?'
274: '@'
275: '['
276: ']'
277: '^'
278: '_'
279: '`'
280: '{'
281: '|'
282: '}'
283: '~'
284: '\'
285: '"'
286: 'e'
287: 'E'
288: 't'
289: 'r'
290: 'u'
291: 'e'
292: 'f'
293: 'a'
294: 'l'
295: 's'
296: 'e'
297: ' '
298: '!'
299: '#'
300: '$'
301: '%'
302: '&'
303: '''
304: '\'
305: '('
306: ')'
307: '*'
308: '+'
309: ','
310: '-'
311: '.'
312: '/'
313: ':'
314: ';'
315: '<'
316: '='
317: '>'
318: '?'
319: '@'
320: '['
321: ']'
322: '^'
323: '_'
324: '`'
325: '|'
326: '~'
327: '\'
328: '{'
329: '\'
330: '}'
331: ' '
332: '\t'
333: '\n'
334: '\r'
335: 'a'-'z'
336: 'A'-'Z'
337: '0'-'9'
338: \u0100-\U0010ffff
339: 'A'-'Z'
340: 'a'-'z'
341: '0'-'9'
342: \u0100-\U0010ffff
343: .
338: '0'-'9'
339: 'a'-'f'
340: 'A'-'F'
341: '0'-'1'
342: 'A'-'Z'
343: 'a'-'z'
344: '0'-'9'
345: \u0100-\U0010ffff
346: 'A'-'Z'
347: 'a'-'z'
348: '0'-'9'
349: \u0100-\U0010ffff
350: .
*/

File diff suppressed because it is too large Load diff

View file

@ -150,22 +150,23 @@ md_token_FILENUM : 'F' 'I' 'L' 'E' 'N' 'U' 'M' ;
// * true and false (boolean literals) are also keywords, defined above.
md_token_begin : 'b' 'e' 'g' 'i' 'n' ;
md_token_end : 'e' 'n' 'd' ;
md_token_filter : 'f' 'i' 'l' 't' 'e' 'r' ;
md_token_emit : 'e' 'm' 'i' 't' ;
md_token_do : 'd' 'o' ;
md_token_dump : 'd' 'u' 'm' 'p' ;
md_token_edump : 'e' 'd' 'u' 'm' 'p' ;
md_token_if : 'i' 'f' ;
md_token_elif : 'e' 'l' 'i' 'f' ;
md_token_else : 'e' 'l' 's' 'e' ;
md_token_emit : 'e' 'm' 'i' 't' ;
md_token_end : 'e' 'n' 'd' ;
md_token_filter : 'f' 'i' 'l' 't' 'e' 'r' ;
md_token_for : 'f' 'o' 'r' ;
md_token_if : 'i' 'f' ;
md_token_in : 'i' 'n' ;
md_token_while : 'w' 'h' 'i' 'l' 'e' ;
//md_token_all : 'a' 'l' 'l' ;
//md_token_break : 'b' 'r' 'e' 'a' 'k' ;
//md_token_call : 'c' 'a' 'l' 'l' ;
//md_token_continue : 'c' 'o' 'n' 't' 'i' 'n' 'u' 'e' ;
//md_token_do : 'd' 'o' ;
//md_token_eprint : 'e' 'p' 'r' 'i' 'n' 't' ;
//md_token_eprintn : 'e' 'p' 'r' 'i' 'n' 't' 'n' ;
//md_token_func : 'f' 'u' 'n' 'c' ;
@ -177,7 +178,6 @@ md_token_in : 'i' 'n' ;
//md_token_subr : 's' 'u' 'b' 'r' ;
//md_token_tee : 't' 'e' 'e' ;
//md_token_unset : 'u' 'n' 's' 'e' 't' ;
//md_token_while : 'w' 'h' 'i' 'l' 'e' ;
//md_token_map_type : 'm' 'a' 'p' ;
//md_token_num_type : 'n' 'u' 'm' ;
@ -319,6 +319,16 @@ StatementBlock
;
StatementBlockInBraces
// Defining StatementBlock to be emptyable would have been more elegant ...
// I got LR-1 conflicts though. :^/
: "{" "}"
<< dsl.NewASTNodeZary(nil, dsl.NodeTypeStatementBlock) >>
| "{" StatementBlock "}"
<< dsl.Wrap($1) >>
;
// ================================================================
// ASSIGMENT STATEMENTS
@ -329,6 +339,9 @@ BracelessStatement
| EmitStatement
| DumpStatement
| EdumpStatement
// Has braces but does not *end* in braces -- so it requires semicolon after.
| DoWhileLoop
;
Assignment
@ -1153,22 +1166,17 @@ BracefulStatement
: BeginBlock
| EndBlock
| IfChain
| WhileLoop
| ForLoop
;
BeginBlock
: md_token_begin "{" "}"
<< dsl.NewASTNodeZary(nil, dsl.NodeTypeBeginBlock) >>
| md_token_begin "{" StatementBlock "}"
<< dsl.NewASTNodeUnary(nil, $2, dsl.NodeTypeBeginBlock) >>
: md_token_begin StatementBlockInBraces
<< dsl.NewASTNodeUnary(nil, $1, dsl.NodeTypeBeginBlock) >>
;
EndBlock
: md_token_end "{" "}"
<< dsl.NewASTNodeZary(nil, dsl.NodeTypeEndBlock) >>
| md_token_end "{" StatementBlock "}"
<< dsl.NewASTNodeUnary(nil, $2, dsl.NodeTypeEndBlock) >>
| md_token_end "{" StatementBlock "}"
<< dsl.NewASTNodeUnary(nil, $2, dsl.NodeTypeEndBlock) >>
: md_token_end StatementBlockInBraces
<< dsl.NewASTNodeUnary(nil, $1, dsl.NodeTypeEndBlock) >>
;
// ================================================================
@ -1192,18 +1200,31 @@ IfElifStar
;
IfBlock
: md_token_if "(" Rvalue ")" "{" StatementBlock "}"
<< dsl.NewASTNodeBinary($0, $2, $5, dsl.NodeTypeIfItem) >>
: md_token_if "(" Rvalue ")" StatementBlockInBraces
<< dsl.NewASTNodeBinary($0, $2, $4, dsl.NodeTypeIfItem) >>
;
ElifBlock
: md_token_elif "(" Rvalue ")" "{" StatementBlock "}"
<< dsl.NewASTNodeBinary($0, $2, $5, dsl.NodeTypeIfItem) >>
: md_token_elif "(" Rvalue ")" StatementBlockInBraces
<< dsl.NewASTNodeBinary($0, $2, $4, dsl.NodeTypeIfItem) >>
;
ElseBlock
: md_token_else "{" StatementBlock "}"
<< dsl.NewASTNodeUnary($0, $2, dsl.NodeTypeIfItem) >>
: md_token_else StatementBlockInBraces
<< dsl.NewASTNodeUnary($0, $1, dsl.NodeTypeIfItem) >>
;
// ================================================================
// WHILE AND DO-WHILE -LOOPS
WhileLoop
: md_token_while "(" Rvalue ")" StatementBlockInBraces
<< dsl.NewASTNodeBinary($0, $2, $4, dsl.NodeTypeWhileLoop) >>
;
DoWhileLoop
: md_token_do StatementBlockInBraces md_token_while "(" Rvalue ")"
<< dsl.NewASTNodeBinary($0, $1, $4, dsl.NodeTypeDoWhileLoop) >>
;
// ================================================================
@ -1238,14 +1259,12 @@ ElseBlock
// ================================================================
// FOR-LOOPS
// ----------------------------------------------------------------
ForLoopIndex
: LocalVariable
;
// TODO: typedefs on localvars
// ----------------------------------------------------------------
ForLoop
: ForLoopKeyOnly
// | ForLoopKeyValue
| ForLoopKeyValue
// | ForLoopMultipleKeysValue
// | TripleForLoop
;
@ -1255,56 +1274,53 @@ ForLoop
ForLoopKeyOnly
: md_token_for
"("
ForLoopIndex
md_token_in
Rvalue
// TODO:... Mappable (function call, srec, oosvar ... -- or check at CST?)
LocalVariable
md_token_in
Rvalue
")"
"{"
StatementBlock
"}"
StatementBlockInBraces
<<
dsl.NewASTNodeTernary(
$0, // "for"
$2, // k, etc.
$4, // $*, etc.
$7, // { ... }
$6, // { ... }
dsl.NodeTypeForLoopKeyOnly,
);
>>
;
// ----------------------------------------------------------------
//// for(k, v in $*) { ... }
// for(k, v in $*) { ... }
ForLoopKeyValue
: md_token_for
"("
LocalVariable
","
LocalVariable
md_token_in
Rvalue
")"
StatementBlockInBraces
<<
dsl.NewASTNodeQuaternary(
$0, // "for"
$2, // k, etc.
$4, // v, etc.
$6, // $*, etc.
$8, // { ... }
dsl.NodeTypeForLoopKeyValue,
);
>>
;
//ForLoopKeyValue(A) ::=
// md_token_for(F) "("
// ForLoopIndex(K) "," ForLoopIndex(V)
// md_token_in md_token_full_srec
// ")"
// "{"
// StatementBlock(S)
// "}".
//{
// mlr_dsl_ast_node_replace_text(S, "for_full_srec_block");
// A = mlr_dsl_ast_node_alloc_binary(
// F->text,
// MD_AST_NODE_TYPE_FOR_SREC,
// mlr_dsl_ast_node_alloc_binary(
// "variables",
// MD_AST_NODE_TYPE_FOR_VARIABLES,
// K,
// V
// ),
// S
// );
//}
// ForLoopMultipleKeysValue
//// for((k1, k2), v in @*) { ... }
//// for((k1, k2, k3), v in @*) { ... }
//ForLoopMultipleKeysValue(A) ::=
// md_token_for(F) "("
// "(" ForMapKeylist(L) ")" "," ForLoopIndex(V)
// "(" ForMapKeylist(L) ")" "," LocalVariable(V)
// md_token_in md_token_full_oosvar
// ")"
// "{"
@ -1326,25 +1342,6 @@ ForLoopKeyOnly
// );
//}
//ForLoopIndex(A) ::= md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION);
//}
//ForLoopIndex(A) ::= md_token_numeric md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION);
//}
//ForLoopIndex(A) ::= md_token_int md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION);
//}
//ForLoopIndex(A) ::= md_token_float md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION);
//}
//ForLoopIndex(A) ::= md_token_string_literal md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION);
//}
//ForLoopIndex(A) ::= md_token_boolean md_token_non_sigil_name(B). {
// A = mlr_dsl_ast_node_alloc(B->text, MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION);
//}
//ForMapKeylist(A) ::= ForLoopIndex(K). {
// A = mlr_dsl_ast_node_alloc_unary("key_variables", MD_AST_NODE_TYPE_FOR_VARIABLES, K);
//}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -11,9 +11,9 @@ import (
)
const (
numProductions = 180
numStates = 2065
numSymbols = 164
numProductions = 184
numStates = 2097
numSymbols = 169
)
// Stack

File diff suppressed because it is too large Load diff

View file

@ -123,6 +123,8 @@ var TokMap = TokenMap{
"$",
"empty",
";",
"{",
"}",
"=",
"md_token_filter",
"md_token_emit",
@ -199,8 +201,6 @@ var TokMap = TokenMap{
"md_token_panic",
"[",
",",
"{",
"}",
"md_token_IPS",
"md_token_IFS",
"md_token_IRS",
@ -219,6 +219,8 @@ var TokMap = TokenMap{
"md_token_if",
"md_token_elif",
"md_token_else",
"md_token_while",
"md_token_do",
"md_token_for",
"md_token_in",
},
@ -228,84 +230,84 @@ var TokMap = TokenMap{
"$": 1,
"empty": 2,
";": 3,
"=": 4,
"md_token_filter": 5,
"md_token_emit": 6,
"md_token_dump": 7,
"md_token_edump": 8,
"md_token_field_name": 9,
"$[": 10,
"]": 11,
"md_token_braced_field_name": 12,
"md_token_full_srec": 13,
"md_token_oosvar_name": 14,
"@[": 15,
"md_token_braced_oosvar_name": 16,
"md_token_full_oosvar": 17,
"md_token_non_sigil_name": 18,
"||=": 19,
"^^=": 20,
"&&=": 21,
"|=": 22,
"^=": 23,
"<<=": 24,
">>=": 25,
">>>=": 26,
"+=": 27,
".=": 28,
"-=": 29,
"*=": 30,
"/=": 31,
"//=": 32,
"%=": 33,
"**=": 34,
"?": 35,
":": 36,
"||": 37,
"^^": 38,
"&&": 39,
"=~": 40,
"!=~": 41,
"==": 42,
"!=": 43,
">": 44,
">=": 45,
"<": 46,
"<=": 47,
"|": 48,
"^": 49,
"&": 50,
"<<": 51,
">>": 52,
">>>": 53,
"+": 54,
"-": 55,
".+": 56,
".-": 57,
".": 58,
"*": 59,
"/": 60,
"//": 61,
"%": 62,
".*": 63,
"./": 64,
".//": 65,
"!": 66,
"~": 67,
"**": 68,
"(": 69,
")": 70,
"md_token_string_literal": 71,
"md_token_int_literal": 72,
"md_token_float_literal": 73,
"md_token_boolean_literal": 74,
"md_token_M_PI": 75,
"md_token_M_E": 76,
"md_token_panic": 77,
"[": 78,
",": 79,
"{": 80,
"}": 81,
"{": 4,
"}": 5,
"=": 6,
"md_token_filter": 7,
"md_token_emit": 8,
"md_token_dump": 9,
"md_token_edump": 10,
"md_token_field_name": 11,
"$[": 12,
"]": 13,
"md_token_braced_field_name": 14,
"md_token_full_srec": 15,
"md_token_oosvar_name": 16,
"@[": 17,
"md_token_braced_oosvar_name": 18,
"md_token_full_oosvar": 19,
"md_token_non_sigil_name": 20,
"||=": 21,
"^^=": 22,
"&&=": 23,
"|=": 24,
"^=": 25,
"<<=": 26,
">>=": 27,
">>>=": 28,
"+=": 29,
".=": 30,
"-=": 31,
"*=": 32,
"/=": 33,
"//=": 34,
"%=": 35,
"**=": 36,
"?": 37,
":": 38,
"||": 39,
"^^": 40,
"&&": 41,
"=~": 42,
"!=~": 43,
"==": 44,
"!=": 45,
">": 46,
">=": 47,
"<": 48,
"<=": 49,
"|": 50,
"^": 51,
"&": 52,
"<<": 53,
">>": 54,
">>>": 55,
"+": 56,
"-": 57,
".+": 58,
".-": 59,
".": 60,
"*": 61,
"/": 62,
"//": 63,
"%": 64,
".*": 65,
"./": 66,
".//": 67,
"!": 68,
"~": 69,
"**": 70,
"(": 71,
")": 72,
"md_token_string_literal": 73,
"md_token_int_literal": 74,
"md_token_float_literal": 75,
"md_token_boolean_literal": 76,
"md_token_M_PI": 77,
"md_token_M_E": 78,
"md_token_panic": 79,
"[": 80,
",": 81,
"md_token_IPS": 82,
"md_token_IFS": 83,
"md_token_IRS": 84,
@ -324,7 +326,9 @@ var TokMap = TokenMap{
"md_token_if": 97,
"md_token_elif": 98,
"md_token_else": 99,
"md_token_for": 100,
"md_token_in": 101,
"md_token_while": 100,
"md_token_do": 101,
"md_token_for": 102,
"md_token_in": 103,
},
}

View file

@ -2,18 +2,12 @@
TOP OF LIST:
! JSON null needs to be passed through as-is ... somehow ... new mlrval type??
o note json types: string, number, boolean, null, object, array.
* while and do-while statements -- not urgent
~ for-loops -- require localvars as prereq
> for-k, for-kv, for-knv sooner -- stack-frame special cases
> defer triple-for until later
* stack frames
o at cst.State: list.List of StackFrame
o for now: StackFrame containing only hash-map from name to mlrval.
- default to absent (no hoisting)
- no scope-walks needed for for-loops
* for-knv
o defer triple-for until later
! quoted NIDX
- how with whitespace regex -- ?
@ -161,3 +155,4 @@ NITS/NON-IMMEDIATE:
! systime printing out in scientific notation :(
! head early-out -- cite the relevant issue & fix the right way ...
* relnotes: label b,i,x vs x,i,b change
* put -- multiple -f? as in C impl?

View file

@ -239,3 +239,18 @@ echo; run_mlr --opprint --from u/s.dkvp put '$z = truncate($a, 1)'
echo; run_mlr --opprint --from u/s.dkvp put '$z = truncate($a, 2)'
echo; run_mlr --opprint --from u/s.dkvp put '$z = truncate($a, 3)'
echo; run_mlr --opprint --from u/s.dkvp put '$z = truncate($a, 4)'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k in $*) { emit { "foo" : "bar" } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k in $*) { emit { "foo" : k } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k in $*) { emit { k: "bar" } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k in $*) { emit { k : k } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k,v in $*) { emit { "foo" : "bar" } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k,v in $*) { emit { "foo" : v } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k,v in $*) { emit { k: "bar" } }'
echo; run_mlr --from u/s.dkvp head -n 2 then put -q 'for (k,v in $*) { emit { k : v } }'
echo; run_mlr --from u/s.dkvp put '$z = 0; while ($z < $i) {$z += 1}'
echo; run_mlr --from u/s.dkvp put '$z = 0; do {$z += 1} while ($z < $i)'
echo; run_mlr --from u/s.dkvp put '$z = 10; while ($z < $i) {$z += 1}'
echo; run_mlr --from u/s.dkvp put '$z = 10; do {$z += 1} while ($z < $i)'

View file

@ -2478,3 +2478,147 @@ pan pan 1 0.3467901443380824 0.7268028627434533 pan
eks pan 2 0.7586799647899636 0.5221511083334797 eks
wye wye 3 0.20460330576630303 0.33831852551664776 wye
eks wye 4 0.38139939387114097 0.13418874328430463 eks
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k in $*) { emit { "foo" : "bar" } }
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k in $*) { emit { "foo" : k } }
foo=a
foo=b
foo=i
foo=x
foo=y
foo=a
foo=b
foo=i
foo=x
foo=y
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k in $*) { emit { k: "bar" } }
a=bar
b=bar
i=bar
x=bar
y=bar
a=bar
b=bar
i=bar
x=bar
y=bar
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k in $*) { emit { k : k } }
a=a
b=b
i=i
x=x
y=y
a=a
b=b
i=i
x=x
y=y
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k,v in $*) { emit { "foo" : "bar" } }
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
foo=bar
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k,v in $*) { emit { "foo" : v } }
foo=pan
foo=pan
foo=1
foo=0.3467901443380824
foo=0.7268028627434533
foo=eks
foo=pan
foo=2
foo=0.7586799647899636
foo=0.5221511083334797
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k,v in $*) { emit { k: "bar" } }
a=bar
b=bar
i=bar
x=bar
y=bar
a=bar
b=bar
i=bar
x=bar
y=bar
----------------------------------------------------------------
mlr --from u/s.dkvp head -n 2 then put -q for (k,v in $*) { emit { k : v } }
a=pan
b=pan
i=1
x=0.3467901443380824
y=0.7268028627434533
a=eks
b=pan
i=2
x=0.7586799647899636
y=0.5221511083334797
----------------------------------------------------------------
mlr --from u/s.dkvp put $z = 0; while ($z < $i) {$z += 1}
a=pan,b=pan,i=1,x=0.3467901443380824,y=0.7268028627434533,z=1
a=eks,b=pan,i=2,x=0.7586799647899636,y=0.5221511083334797,z=2
a=wye,b=wye,i=3,x=0.20460330576630303,y=0.33831852551664776,z=3
a=eks,b=wye,i=4,x=0.38139939387114097,y=0.13418874328430463,z=4
----------------------------------------------------------------
mlr --from u/s.dkvp put $z = 0; do {$z += 1} while ($z < $i)
a=pan,b=pan,i=1,x=0.3467901443380824,y=0.7268028627434533,z=1
a=eks,b=pan,i=2,x=0.7586799647899636,y=0.5221511083334797,z=2
a=wye,b=wye,i=3,x=0.20460330576630303,y=0.33831852551664776,z=3
a=eks,b=wye,i=4,x=0.38139939387114097,y=0.13418874328430463,z=4
----------------------------------------------------------------
mlr --from u/s.dkvp put $z = 10; while ($z < $i) {$z += 1}
a=pan,b=pan,i=1,x=0.3467901443380824,y=0.7268028627434533,z=10
a=eks,b=pan,i=2,x=0.7586799647899636,y=0.5221511083334797,z=10
a=wye,b=wye,i=3,x=0.20460330576630303,y=0.33831852551664776,z=10
a=eks,b=wye,i=4,x=0.38139939387114097,y=0.13418874328430463,z=10
----------------------------------------------------------------
mlr --from u/s.dkvp put $z = 10; do {$z += 1} while ($z < $i)
a=pan,b=pan,i=1,x=0.3467901443380824,y=0.7268028627434533,z=11
a=eks,b=pan,i=2,x=0.7586799647899636,y=0.5221511083334797,z=11
a=wye,b=wye,i=3,x=0.20460330576630303,y=0.33831852551664776,z=11
a=eks,b=wye,i=4,x=0.38139939387114097,y=0.13418874328430463,z=11

View file

@ -88,4 +88,15 @@ echo; run_mlr -n put -v 'if (NR == 1) { $z = 100 } elif (NR == 2) { $z = 200 }'
echo; run_mlr -n put -v 'if (NR == 1) { $z = 100 } elif (NR == 2) { $z = 200 } else { $z = 900 }'
echo; run_mlr -n put -v 'if (NR == 1) { $z = 100 } elif (NR == 2) { $z = 200 } elif (NR == 3) { $z = 300 } else { $z = 900 }'
echo; run_mlr -n put -v 'for (k in $*) { emit { k : k} }'
echo; run_mlr -n put -v 'for (k in $*) { emit { k : k } }'
echo; run_mlr -n put -v 'begin {}'
echo; run_mlr -n put -v 'begin {1}'
echo; run_mlr -n put -v 'end {}'
echo; run_mlr -n put -v 'end {1}'
echo; run_mlr -n put -v 'if (1) {}'
echo; run_mlr -n put -v 'if (1) {2}'
echo; run_mlr -n put -v 'for (k in $*) {}'
echo; run_mlr -n put -v 'for (k in $*) {2}'
echo; run_mlr -n put -v 'while (false) {}'
echo; run_mlr -n put -v 'do {} while (false)'

View file

@ -736,6 +736,7 @@ begin{}
RAW AST:
* StatementBlock
* BeginBlock
* StatementBlock
@ -760,6 +761,7 @@ end{}
RAW AST:
* StatementBlock
* EndBlock
* StatementBlock
@ -818,7 +820,9 @@ begin{} end {}
RAW AST:
* StatementBlock
* BeginBlock
* StatementBlock
* EndBlock
* StatementBlock
@ -1061,9 +1065,9 @@ RAW AST:
----------------------------------------------------------------
mlr -n put -v for (k in $*) { emit { k : k} }
mlr -n put -v for (k in $*) { emit { k : k } }
DSL EXPRESSION:
for (k in $*) { emit { k : k} }
for (k in $*) { emit { k : k } }
RAW AST:
* StatementBlock
* ForLoopKeyOnly "for"
@ -1076,3 +1080,131 @@ RAW AST:
* LocalVariable "k"
* LocalVariable "k"
----------------------------------------------------------------
mlr -n put -v begin {}
DSL EXPRESSION:
begin {}
RAW AST:
* StatementBlock
* BeginBlock
* StatementBlock
----------------------------------------------------------------
mlr -n put -v begin {1}
DSL EXPRESSION:
begin {1}
RAW AST:
* StatementBlock
* BeginBlock
* StatementBlock
* BareBoolean
* IntLiteral "1"
----------------------------------------------------------------
mlr -n put -v end {}
DSL EXPRESSION:
end {}
RAW AST:
* StatementBlock
* EndBlock
* StatementBlock
----------------------------------------------------------------
mlr -n put -v end {1}
DSL EXPRESSION:
end {1}
RAW AST:
* StatementBlock
* EndBlock
* StatementBlock
* BareBoolean
* IntLiteral "1"
----------------------------------------------------------------
mlr -n put -v if (1) {}
DSL EXPRESSION:
if (1) {}
RAW AST:
* StatementBlock
* IfChain
* IfItem "if"
* IntLiteral "1"
* StatementBlock
----------------------------------------------------------------
mlr -n put -v if (1) {2}
DSL EXPRESSION:
if (1) {2}
RAW AST:
* StatementBlock
* IfChain
* IfItem "if"
* IntLiteral "1"
* StatementBlock
* BareBoolean
* IntLiteral "2"
----------------------------------------------------------------
mlr -n put -v for (k in $*) {}
DSL EXPRESSION:
for (k in $*) {}
RAW AST:
* StatementBlock
* ForLoopKeyOnly "for"
* LocalVariable "k"
* FullSrec "$*"
* StatementBlock
----------------------------------------------------------------
mlr -n put -v for (k in $*) {2}
DSL EXPRESSION:
for (k in $*) {2}
RAW AST:
* StatementBlock
* ForLoopKeyOnly "for"
* LocalVariable "k"
* FullSrec "$*"
* StatementBlock
* BareBoolean
* IntLiteral "2"
----------------------------------------------------------------
mlr -n put -v while (false) {}
DSL EXPRESSION:
while (false) {}
RAW AST:
* StatementBlock
* WhileLoop "while"
* BoolLiteral "false"
* StatementBlock
----------------------------------------------------------------
mlr -n put -v do {} while (false)
DSL EXPRESSION:
do {} while (false)
RAW AST:
* StatementBlock
* DoWhileLoop "do"
* StatementBlock
* BoolLiteral "false"