static void enclosureEnd(Enclosure ended) { switch (ended.type) { case NT.IF: break; case NT.MEMBER_TUPLE: { AST_Tuple tuple = (AST_Tuple)ended.node; DataType_Tuple tupleType; ValueKind tupleKind; getTuple_Type_Kind(tuple, out tupleType, out tupleKind); tuple.result = new IR { irType = NT.TUPLE, dType = tupleType, dKind = tupleKind }; // TODO: only allow members } break; case NT.FUNCTION: if (!isDefineFase) { swap(ref instructions, ref ((IR_Function)ended.node.result).block); } break; case NT.STRUCT: { var structNode = (AST_Struct)ended.node; var structType = (DataType_Struct)structNode.result.dType; DataType[] members; if (structNode.inherits != null) { members = new DataType[structType.members.Length + 1]; members[0] = structNode.inherits.result.dType; structType.members.CopyTo(members, 1); } else { members = new DataType[structType.members.Length]; structType.members.CopyTo(members, 0); } structNode.result = instructions.Add(new IR { irType = NT.STRUCT, dType = structType, dKind = ValueKind.STATIC_TYPE }); if (structNode.inherits != null) { if (structNode.inherits.result.dKind != ValueKind.STATIC_TYPE || !(structNode.inherits.result.dType is DataType_Struct)) { throw Jolly.addError(structNode.inherits.location, "Can only inherit from other structs"); } structType.inherits = (DataType_Struct)structNode.inherits.result.dType; } } break; case NT.OBJECT: break; default: throw Jolly.addError(ended.node.location, "Internal compiler error: illigal node used as enclosure"); } // switch(ended.type) }
static IR packTuple(AST_Tuple tuple, DataType_Tuple tupleType) { IR_Allocate alloc = new IR_Allocate { dType = tupleType }; tuple.values.forEach((val, i) => { IR member = instructions.Add(IR.getMember(alloc, tupleType.members[i], i)); instructions.Add(IR.operation <IR_Assign>(member, val.result, null)); }); return(alloc); }
} // parseParenthesisOpen() void parseParenthesisClose() { currentTokenKind = TokenKind.VALUE; Operator op; while ((op = operators.PopOrDefault()).operation != NT.PARENTHESIS_OPEN) { if (op.operation == NT.UNDEFINED) { throw Jolly.unexpected(token); } pushOperator(op); } Context context = contextStack.Pop(); while (context.kind != Context.Kind.GROUP) { contextEnd(context); context = contextStack.Pop(); } if (context.isFunctionCall) { AST_Node[] arguments = null; AST_Node node = values.Pop(); if (node != null) { AST_Tuple tuple = node as AST_Tuple; arguments = tuple != null && !tuple.closed ? tuple.values.ToArray() : new AST_Node[] { node }; values.Pop(); // Pop extra null } var call = new AST_FunctionCall(token.location, context.target, arguments ?? new AST_Node[0]); values.Push(call); ast.Add(call); } else if (values.PeekOrDefault()?.nodeType == NT.TUPLE) { var tup = ((AST_Tuple)values.Pop()); // Close list so you can't add to it: (a, b), c tup.closed = true; tup.memberCount = ast.Count - context.index; if (operators.PeekOrDefault().operation == NT.GET_MEMBER) { operators.Pop(); // Remove GET_MEMBER tup.membersFrom = values.Pop(); tup.nodeType = NT.MEMBER_TUPLE; } values.Push(tup); ast.Insert(context.index, tup); } } // parseParenthesisClose()
static void getTuple_Type_Kind(AST_Tuple tuple, out DataType_Tuple tupleType, out ValueKind tupleKind) { ValueKind _tupleKind = 0; DataType_Tuple _tupleType = new DataType_Tuple(tuple.values.Count); tuple.values.forEach((val, i) => { _tupleKind |= val.result.dKind; _tupleType.members[i] = val.result.dType; }); if ((_tupleKind & (ValueKind.STATIC_TYPE | ValueKind.STATIC_FUNCTION)) != 0) { if ((_tupleKind & ~(ValueKind.STATIC_TYPE | ValueKind.STATIC_FUNCTION)) != 0) { throw Jolly.addError(tuple.location, "Tuple mixes values and types"); } } else if ((_tupleKind & (ValueKind.ADDRES | ValueKind.STATIC_VALUE | ValueKind.VALUE)) == 0) { throw Jolly.addError(tuple.location, "Invalid tuple type"); } tupleKind = _tupleKind; tupleType = (DataType_Tuple)DataType.makeUnique(_tupleType); }
static void contextEnd(Context ended) { switch (ended.kind) { case Context.Kind.TUPLE: { AST_Tuple tuple = (AST_Tuple)ended.target; DataType_Tuple tupleType; ValueKind tupleKind; getTuple_Type_Kind(tuple, out tupleType, out tupleKind); // If the tuple doesn't contain names pack it if ((tupleKind & (ValueKind.ADDRES | ValueKind.STATIC_TYPE)) == 0) { tuple.result = instructions.Add(new IR_Read { target = packTuple(tuple, tupleType), dType = tupleType }); } else { tuple.result = new IR { irType = NT.TUPLE, dType = tupleType, dKind = tupleKind }; } } break; case Context.Kind.IF_CONDITION: { var ifNode = (AST_If)ended.target; load(ifNode.condition); implicitCast(ref ifNode.condition.result, Lookup.I1); ifNode.result = instructions.Add(new IR_If { condition = ifNode.condition.result, ifBlock = instructions }); contextStack.Push(new Context(cursor + ifNode.ifCount, Context.Kind.IF_TRUE) { target = ifNode }); instructions = new IRList(); } break; case Context.Kind.IF_TRUE: { var ifNode = (AST_If)ended.target; var ifIR = (IR_If)ifNode.result; swap(ref instructions, ref ifIR.ifBlock); if (ifNode.elseCount > 0) { ifIR.elseBlock = instructions; instructions = new IRList(); contextStack.Push(new Context(cursor + ifNode.elseCount, Context.Kind.IF_FALSE) { target = ifNode }); } } break; case Context.Kind.IF_FALSE: { var ifNode = (AST_If)ended.target; var ifIR = (IR_If)ifNode.result; swap(ref instructions, ref ifIR.elseBlock); } break; case Context.Kind.LOGIC_OR: { var lor = (AST_Logic)ended.target; var lorIR = (IR_Logic)lor.result; load(lor.a); implicitCast(ref lor.a.result, Lookup.I1); swap(ref instructions, ref lorIR.block); lorIR.a = lor.a.result; } break; case Context.Kind.LOGIC_AND: { var land = (AST_Logic)ended.target; var landIR = (IR_Logic)land.result; load(land.a); implicitCast(ref land.a.result, Lookup.I1); swap(ref instructions, ref landIR.block); landIR.a = land.a.result; } break; case Context.Kind.DECLARATION: { // type inference var declaration = (AST_Declaration)ended.target; var alloc = (IR_Allocate)declaration.result; if (alloc.dType == Lookup.AUTO || !alloc.initialized) { throw Jolly.addError(declaration.location, "Auto variables must be initialized."); } } break; case Context.Kind.FUNCTION_DECLARATION: { // The declaration ends after the return values and arguments are parsed. var function = (AST_Function)enclosure.node; var functionType = (DataType_Function)function.result.dType; functionType.returns = function.returns.result.dType; DataType.makeUnique(ref function.result.dType); cursor = enclosure.end; // Skip to end of function enclosure } break; } // switch(ended.kind) }
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()