void parseBracketClose() { currentTokenKind = TokenKind.VALUE; Operator op; while ((op = operators.PopOrDefault()).operation != NT.BRACKET_OPEN) { if (op.operation == NT.UNDEFINED) { throw Jolly.unexpected(token); } pushOperator(op); } Context context = contextStack.Pop(); while (context.kind != Context.Kind.SUBSCRIPT) { contextEnd(context); context = contextStack.Pop(); } if (context.hasColon) { var node = values.Peek(); if (node.nodeType == NT.MODIFY_TYPE) { ((AST_ModifyType)node).target = context.target; } else if (node.nodeType != NT.SLICE) { throw Jolly.unexpected(node); } } else { AST_Node a = values.PopOrDefault(); if (a == null) { var mod = new AST_ModifyType(op.location, context.target, AST_ModifyType.TO_ARRAY); ast.Add(mod); values.Push(mod); return; } var opNode = new AST_Operation(token.location, NT.SUBSCRIPT, a, null, false); values.Push(opNode); ast.Add(opNode); } if (values.Peek() == null) { values.Pop(); } }
static void inferOperands(AST_Operation op) { if (op.leftToRight) { op.a.infer?.Invoke(op.a, op.b, instructions); op.b?.infer?.Invoke(op.b, op.a, instructions); } else { op.b?.infer?.Invoke(op.b, op.a, instructions); op.a.infer?.Invoke(op.a, op.b, instructions); } }
static void analyseNode(AST_Node node) { Action <AST_Node> action; if (!analysers.TryGetValue(node.nodeType, out action)) { throw Jolly.unexpected(node); } // TODO: Find a better way to do this AST_Operation op = node as AST_Operation; if (op != null) { inferOperands(op); } action(node); }
void pushOperator(Operator op) { AST_Node a, b = null; if (op.valCount == 2) { b = values.PopOrDefault(); a = values.PopOrDefault(); if (op.operation == NT.COMMA) { if (a == null) { values.Push(null); if (!(b is AST_Tuple)) { var tup = new AST_Tuple(b.location, NT.TUPLE); tup.values.Add(b); values.Push(tup); return; } values.Push(b); return; } AST_Tuple tuple = a as AST_Tuple; if (tuple?.closed ?? true) { tuple = new AST_Tuple(b.location, NT.TUPLE); tuple.values.Add(a); } tuple.values.Add(b); values.Push(tuple); return; } else if (op.operation == NT.SLICE) { if (a == null & b == null) { var mod = new AST_ModifyType(op.location, null, AST_ModifyType.TO_SLICE); values.Push(mod); ast.Add(mod); return; } // Slice allows a value to be null var slice = (a == null) ? new AST_Operation(op.location, NT.SLICE, b, null, true) : new AST_Operation(op.location, NT.SLICE, a, b, true); values.Push(slice); ast.Add(slice); return; } if (a == null) { throw Jolly.addError(op.location, "Expecting 2 values"); } if (op.operation == NT.GET_MEMBER && b.nodeType == NT.NAME) { b.nodeType = NT.MEMBER_NAME; } } else { a = values.PopOrDefault(); if (a == null) { throw Jolly.addError(op.location, "Invalid expression term"); } } if (op.isSpecial) { if (op.operation == NT.LOGIC_AND) { int memberCount = ast.Count - op.operatorIndex; var logic = new AST_Logic(op.location, NT.LOGIC_OR, memberCount, memberCount, condition: a, a: b, b: null); values.Push(logic); ast.Insert(op.operatorIndex, logic); return; } else if (op.operation == NT.LOGIC_OR) { int memberCount = ast.Count - op.operatorIndex; var logic = new AST_Logic(op.location, NT.LOGIC_AND, memberCount, memberCount, condition: a, a: b, b: null); values.Push(logic); ast.Insert(op.operatorIndex, logic); return; } else if (op.operation == NT.TERNARY) { Context context = contextStack.Pop(); while (context.kind != Context.Kind.TERNARY) { contextEnd(context); context = contextStack.Pop(); } context.target = a; contextStack.Push(context); values.Push(b); return; } else if (op.operation == NT.TERNARY_SELECT) { Context context = contextStack.Pop(); while (context.kind != Context.Kind.TERNARY) { contextEnd(context); context = contextStack.Pop(); } int memberCount = ast.Count - context.index, count = op.operatorIndex - context.index; var logic = new AST_Logic(op.location, NT.TERNARY, memberCount, count, context.target, a, b); values.Push(logic); ast.Insert(context.index, logic); return; } Jolly.addNote(op.location, "Compiler: unnecessary operator marked special {0}".fill(op.operation)); } // if(op.isSpecial) AST_Operation opNode = new AST_Operation(op.location, op.operation, a, b, op.leftToRight); values.Push(opNode); ast.Add(opNode); } // pushOperator()