public AST_Operation(SourceLocation loc, NT operation, AST_Node a, AST_Node b, bool leftToRight) : base(loc, operation) { this.leftToRight = leftToRight; this.a = a; this.b = b; }
static void getTypeFromName(AST_Node node) { if (node.result?.dType != null && (node.result.dType.flags & DataType.Flags.UNFINISHED) == 0) { return; } if (enclosure.type == NT.MEMBER_TUPLE) { node.result = operatorGetMember(ref ((AST_Tuple)enclosure.node).membersFrom, node); return; } AST_Symbol name = (AST_Symbol)node; name.symbol = enclosure.scope.searchSymbol(name.text); if (name.symbol == null) { throw Jolly.addError(name.location, "The name \"{0}\" does not exist in the current context".fill(name.text)); } name.result = name.symbol.declaration; }
public static IRList analyse(List <AST_Node> program, SymbolTable globalScope) { Analyser.program = program; instructions = new IRList(); contextStack = new ContextStack(16); enclosureStack = new EnclosureStack(16); contextStack.Push(new Context(int.MaxValue, Context.Kind.STATEMENT)); // Just put something on the stack enclosureStack.Push(new Enclosure(NT.GLOBAL, null, globalScope, int.MaxValue)); program.forEach((n, i) => Console.WriteLine("{0}: {1}".fill(i, n))); Console.WriteLine(); for (cursor = 0; cursor < program.Count; incrementCursor(ref cursor)) { Action <AST_Node> action; AST_Node node = program[cursor]; if (typeDefinitionAnalysers.TryGetValue(node.nodeType, out action)) { action(node); } } isDefineFase = false; for (cursor = 0; cursor < program.Count; incrementCursor(ref cursor)) { analyseNode(program[cursor]); } return(instructions); }
static void modifyType(AST_Node node) { AST_ModifyType mod = (AST_ModifyType)node; if (mod.target.result.dKind != ValueKind.STATIC_TYPE) { throw Jolly.addError(mod.target.location, "Not a type"); } if ((mod.target.result.dType.flags & DataType.Flags.INSTANTIABLE) == 0) { throw Jolly.addError(mod.target.location, "The type {0} is not instantiable.".fill(mod.target.result.dType)); } // TODO: Fix switch (mod.toType) { case AST_ModifyType.TO_SLICE: case AST_ModifyType.TO_ARRAY: mod.result = new IR { irType = NT.BASETYPE, dType = new DataType_Array_Data(mod.target.result.dType), dKind = ValueKind.STATIC_TYPE }; break; case AST_ModifyType.TO_POINTER: case AST_ModifyType.TO_NULLABLE: // TODO: Make regular pointer non nullable mod.result = new IR { irType = NT.BASETYPE, dType = new DataType_Reference(mod.target.result.dType), dKind = ValueKind.STATIC_TYPE }; break; } DataType.makeUnique(ref mod.result.dType); mod.result.dKind = mod.target.result.dKind; }
} // parseOperator() void parseBraceOpen() { currentTokenKind = TokenKind.OPERATOR; Operator prevOp = operators.PeekOrDefault(); // valCount of default(Op) == 0 while (prevOp.valCount > 0 && prevOp.precedence < 14) { pushOperator(operators.Pop()); prevOp = operators.PeekOrDefault(); } AST_Node targetType = null; if (prevTokenKind == TokenKind.VALUE) { targetType = values.Pop(); } values.Push(null); operators.Push(new Operator(255, 0, false, NT.BRACE_OPEN, false, token.location)); contextStack.Push(new Context(ast.Count, Context.Kind.OBJECT) { target = targetType }); }
public Enclosure(NT t, AST_Node n, SymbolTable s, int e) { scope = s; type = t; node = n; end = e; }
void parseBraceClose() { currentTokenKind = TokenKind.VALUE; Operator op; while ((op = operators.PopOrDefault()).operation != NT.BRACE_OPEN) { if (op.operation == NT.UNDEFINED) { throw Jolly.unexpected(token); } pushOperator(op); } Context context = contextStack.Pop(); while (context.kind != Context.Kind.OBJECT) { contextEnd(context); context = contextStack.Pop(); } AST_Node[] initializers = null; if (context.index != ast.Count) { AST_Node node = values.Pop(); initializers = (node as AST_Tuple)?.values.ToArray() ?? new AST_Node[] { node }; } bool isArray = initializers?.All(i => i.nodeType != NT.INITIALIZER) ?? false; if (!isArray) { initializers?.forEach(i => { if (i.nodeType != NT.INITIALIZER) { throw Jolly.addError(i.location, "Invalid intializer member declarator"); } ((AST_Operation)i).a.nodeType = NT.OBJECT_MEMBER_NAME; }); } var _object = new AST_Object(op.location, NT.OBJECT) { memberCount = ast.Count - context.index, inferFrom = context.target, nodeType = NT.OBJECT, isArray = isArray, }; if (values.Peek() == null) { values.Pop(); } values.Push(_object); ast.Insert(context.index, _object); }
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 declare(AST_Node node) { if (node.result?.dType != null) { skipSymbol(node); return; } var enclosureNode = (AST_Scope)enclosure.node; var declaration = (AST_Declaration)node; DataType allocType = declaration.typeFrom.result.dType; // Has to be instantiable if ((allocType.flags & DataType.Flags.INSTANTIABLE) == 0) { throw Jolly.addError(node.location, "The type {0} is not instantiable.".fill(allocType)); } switch (enclosure.type) { case NT.FUNCTION: case NT.GLOBAL: { var alloc = new IR_Allocate { dType = allocType }; declaration.symbol.declaration = alloc; declaration.result = instructions.Add(alloc); // Variable is an argument if (context.kind == Context.Kind.FUNCTION_DECLARATION) { var function = (AST_Function)enclosure.node; var functionType = (DataType_Function)function.result.dType; functionType.arguments[function.finishedArguments] = allocType; function.finishedArguments += 1; cursor = enclosure.end; } } break; case NT.STRUCT: { ((DataType_Struct)enclosureNode.result.dType).finishDefinition(declaration.text, allocType); } break; default: throw Jolly.addError(declaration.location, "Cannot define a variable here"); } if (allocType == Lookup.AUTO) { declaration.infer = inferAutoVariable; contextStack.Push(new Context(declaration.memberCount + cursor, Context.Kind.DECLARATION) { target = declaration }); } }
} // 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()
void parseTemplateArgument() { currentTokenKind = TokenKind.VALUE; Token name = tokens[cursor += 1]; if (name.type != TT.IDENTIFIER) { Jolly.unexpected(name); } AST_Template node = new AST_Template(name.location); AST_Node typeFrom = null; if (prevTokenKind == TokenKind.VALUE) { if (defineMode != DefineMode.TEMPLATE) { throw Jolly.unexpected(token); } typeFrom = values.Pop(); Debug.Assert(typeFrom != null); } DefineMode inferrableDefineMode = (DefineMode.TEMPLATE | DefineMode.ARGUMENT) & defineMode; if (canDefine && inferrableDefineMode != 0) { if (scope.template.TryGetValue(name.text, out node.item)) { if ((node.item.canBeInferredBy & defineMode) == DefineMode.TEMPLATE) { throw Jolly.addError(name.location, "Trying to redefine template argument ${0}".fill(name.text)); } node.item.canBeInferredBy |= inferrableDefineMode; } else { scope.template.Add(name.text, node.item = new TemplateItem { canBeInferredBy = inferrableDefineMode, constantValue = typeFrom, location = node.location, defineIndex = defineIndex++, }); } } else { node.name = name.text; } values.Push(node); ast.Add(node); }
static void dereference(AST_Node node) { IR refIR = (node as AST_Operation)?.a.result ?? node.result; var reference = refIR.dType as DataType_Reference; if (isStatic(refIR.dKind) || reference == null) { throw Jolly.addError((node as AST_Operation ?? node).location, "Cannot dereference this"); } node.result = instructions.Add(new IR_Dereference { target = refIR, dType = reference.referenced }); }
static bool inferAutoVariable(AST_Node i, AST_Node other, IRList instructions) { DataType type = other.result.dType; var declaration = (AST_Declaration)i; // Has to be instantiable and not unfinished if ((type.flags & (DataType.Flags.INSTANTIABLE | DataType.Flags.UNFINISHED)) != DataType.Flags.INSTANTIABLE) { throw Jolly.addError(declaration.location, "The inferred type {0} is not instantiable.".fill(type)); } declaration.symbol.declaration.dType = type; return(true); }
void modifyType(byte toType) { AST_Node target = values.PopOrDefault(); if (target == null) { throw Jolly.unexpected(token); } currentTokenKind = TokenKind.VALUE; var mod = new AST_ModifyType(token.location, target, toType); values.Push(mod); ast.Add(mod); }
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); }
static void assign(AST_Node node) { var op = (AST_Operation)node; if ((op.a.result.dKind & ~ValueKind.ADDRES) != 0) { throw Jolly.addError(op.location, "Cannot assign to this"); } load(op.b); implicitCast(ref op.b.result, op.a.result.dType); //TODO: Assign to tuple containing names: someStruct.(a, b) = (0, 1); if (op.a.result.irType == NT.ALLOCATE) { ((IR_Allocate)op.a.result).initialized = true; } op.result = instructions.Add(IR.operation <IR_Assign>(op.a.result, op.b.result, null)); }
/*########### * Hooks ###########*/ static bool inferObject(AST_Node i, AST_Node other, IRList instructions) { var _object = (AST_Object)i; var inferFrom = _object.inferFrom?.result ?? other.result; var errLoc = _object.inferFrom?.location ?? other.location; if ((inferFrom.dType.flags & DataType.Flags.INSTANTIABLE) == 0) { throw Jolly.addError(errLoc, "Cannot instantiate auto"); } // TODO: Add further type checks int end = _object.startIndex + _object.memberCount; _object.result.dType = inferFrom.dType; enclosureStack.Push(new Enclosure(NT.OBJECT, _object, enclosure.scope, end)); for (int j = _object.startIndex; j < end; incrementCursor(ref j)) { analyseNode(program[j]); } return(true); }
static void load(AST_Node node) { if ((node.result.dKind & ValueKind.ADDRES) == 0) { return; } if (node.nodeType == NT.TUPLE) { node.result = packTuple((AST_Tuple)node, ((DataType_Tuple)node.result.dType)); } AST_Symbol name = node as AST_Symbol; if (name.symbol.isGeneric) { } node.result = instructions.Add(new IR_Read { target = node.result, dType = node.result.dType }); }
static void basicOperator <T>(AST_Node node, Func <object, object, object> staticExec) where T : IR_Operation, new() { var op = (AST_Operation)node; load(op.a); load(op.b); IR aIR = op.a.result, bIR = op.b.result; if (aIR.dType != bIR.dType) { // TODO: This always tries to cast's the left type to the right type then right to left, // maybe this should be decided by the operator's left to right'ness. Cast cast; if (Lookup.implicitCast.get(aIR.dType, bIR.dType, out cast)) { aIR = cast(aIR, bIR.dType); } else if (Lookup.implicitCast.get(aIR.dType, bIR.dType, out cast)) { bIR = cast(bIR, aIR.dType); } else { throw Jolly.addError(op.location, "Cannot use operator on {0} and {1}".fill(aIR.dType, bIR.dType)); } } if ((aIR.dKind & bIR.dKind & ValueKind.STATIC_VALUE) != 0 && staticExec != null) { op.result = new IR_Literal { dType = aIR.dType, data = staticExec(((IR_Literal)aIR).data, ((IR_Literal)bIR).data) }; return; } op.result = instructions.Add(new T { a = aIR, b = bIR, dType = aIR.dType }); }
void parseBracketOpen() { currentTokenKind = TokenKind.OPERATOR; if (prevTokenKind == TokenKind.OPERATOR) { throw Jolly.unexpected(token); } AST_Node target = values.PopOrDefault(); if (target == null) { throw Jolly.unexpected(token); } values.Push(null); operators.Push(new Operator(255, 0, false, NT.BRACKET_OPEN, false, token.location)); contextStack.Push(new Context(ast.Count, Context.Kind.SUBSCRIPT) { target = target }); }
static IR operatorGetMember(ref AST_Node a, AST_Node b) { bool isName = false; string name = null; int index = 0; switch (b.nodeType) { case NT.NAME: { isName = true; name = ((AST_Symbol)b).text; } break; case NT.LITERAL: { if (b.result.dType != Lookup.I32) { goto default; } index = (int)(long)((IR_Literal)b.result).data; } break; default: throw Jolly.addError(a.location, "The right-hand operant of member access can only be a symbol or index"); } if (a.result.dKind == ValueKind.ADDRES) { var iterator = a.result; var definition = isName ? iterator.dType.getMember(iterator, name, instructions) : iterator.dType.getMember(iterator, index, instructions); // TODO: Differentiate between not found and doesn't implement getMember while (definition == null) { dereference(a); iterator = a.result; definition = isName ? iterator.dType.getMember(iterator, name, instructions) : iterator.dType.getMember(iterator, index, instructions); } if (definition == null) { throw Jolly.addError(b.location, "Type does not contain a member {0}".fill(name)); } return(definition); } else if (a.result.dKind == ValueKind.STATIC_TYPE) { if (!isName) { throw new ParseException(); } // Get static member var definition = ((AST_Symbol)a).symbol.getChildSymbol(name); if (definition == null) { throw Jolly.addError(b.location, "The type does not contain a member \"{0}\"".fill(name)); } return(definition.declaration); } else { throw Jolly.unexpected(a); } }
public ExpressionParser parse(bool allowEarlyExit) { AST_Node _value = null; Debug.Assert(contextStack.Count > 0); // Context must be set for (token = parseData.tokens[parseData.cursor]; token.type != terminator & parseData.cursor < end; token = parseData.tokens[parseData.cursor += 1]) { switch (token.type) { case TT.IDENTIFIER: parseIdentifier(); break; case TT.COMMA: parseComma(); break; case TT.PARENTHESIS_OPEN: parseParenthesisOpen(); break; case TT.PARENTHESIS_CLOSE: parseParenthesisClose(); break; case TT.BRACKET_OPEN: parseBracketOpen(); break; case TT.BRACKET_CLOSE: parseBracketClose(); break; case TT.BRACE_OPEN: parseBraceOpen(); break; case TT.BRACE_CLOSE: parseBraceClose(); break; case TT.DOLLAR: parseTemplateArgument(); break; case TT.INTEGER_LITERAL: _value = new AST_Node(token.location, NT.LITERAL) { result = INT(token._integer) }; goto case 0; case TT.STRING_LITERAL: _value = new AST_Node(token.location, NT.LITERAL) { result = STRING(token._string) }; goto case 0; case TT.FLOAT_LITERAL: _value = new AST_Node(token.location, NT.LITERAL) { result = FLOAT(token._float) }; goto case 0; case TT.TRUE: _value = new AST_Node(token.location, NT.LITERAL) { result = BOOL(true) }; goto case 0; case TT.FALSE: _value = new AST_Node(token.location, NT.LITERAL) { result = BOOL(false) }; goto case 0; case TT.NULL: _value = new AST_Node(token.location, NT.LITERAL) { result = VOID_PTR() }; goto case 0; case TT.SEMICOLON: if (allowEarlyExit) { goto breakLoop; } else { throw Jolly.unexpected(token); } default: if (token.type >= TT.I1 & token.type <= TT.AUTO) { _value = new AST_Node(token.location, NT.BASETYPE) { result = new IR_Literal { dType = Lookup.getBaseType(token.type), dKind = ValueKind.STATIC_TYPE } }; goto case 0; } if (parseOperator()) { break; } // Failed to parse token throw Jolly.unexpected(token); case 0: // Hacky if (prevTokenKind == TokenKind.VALUE) { throw Jolly.unexpected(token); } currentTokenKind = TokenKind.VALUE; values.Push(_value); break; } prevTokenKind = currentTokenKind; } goto breakLoop; breakLoop: // An early exit is when you exit on a semicolon and not the terminator if (!allowEarlyExit && cursor < end && token.type != terminator) { throw Jolly.unexpected(token); } while (operators.Count > 0) { pushOperator(operators.Pop()); } while (contextStack.Count > 1) { contextEnd(contextStack.Pop()); } return(this); // Make calls chainable: new ExpressionParser(...).parse(); } // parseExpression()
} // parseExpression() void parseIdentifier() { currentTokenKind = TokenKind.VALUE; string name = token.text; AST_Node target = null; // If function it's the return type otherwhise it's the variable type switch (prevTokenKind) { case TokenKind.VALUE: // Pop eventual period and comma operators while (operators.Count > 0) { pushOperator(operators.Pop()); } target = values.Pop(); break; case TokenKind.SEPARATOR: while (contextStack.Peek().kind == Context.Kind.DECLARATION) { contextEnd(contextStack.Pop()); } if (defineMode != DefineMode.ARGUMENT && prevDefinedType != null && contextStack.Peek().kind == Context.Kind.STATEMENT) { target = prevDefinedType; break; } goto default; default: var symbol = new AST_Symbol(token.location, null, name) { templateArguments = parseTemplateArguments() }; values.Push(symbol); ast.Add(symbol); return; } Token nextToken = tokens[cursor + 1]; int startNodeCount = contextStack.Peek().index; if (!canDefine) { throw Jolly.addError(token.location, "Can't define the {0} \"{1}\" here.".fill( (nextToken.type == TT.PARENTHESIS_OPEN) ? "function" : "variable", token.text)); } // Declare if (nextToken.type == TT.PARENTHESIS_OPEN || nextToken.type == TT.LESS) { // Function if (defineMode != DefineMode.STATEMENT) { throw Jolly.addError(token.location, "Can't define the function \"{0}\" here".fill(name)); } DataType_Function functionType = new DataType_Function(); AST_Function functionNode = new AST_Function(token.location); FunctionTable functionTable = new FunctionTable(scope); functionNode.templateArguments = parseTemplate(functionTable); nextToken = tokens[cursor + 1]; functionNode.index = ast.Count; functionNode.symbol = functionTable; functionNode.text = functionType.name = name; functionNode.result = functionTable.declaration = new IR_Function { dType = functionType }; scope.addChild(name, functionTable, true); ast.Insert(startNodeCount, functionNode); functionNode.returnCount = ast.Count - (startNodeCount += 1); // Skip the function node itself cursor += 2; new ExpressionParser(parseData, TT.UNDEFINED, functionTable, DefineMode.ARGUMENT, nextToken.partnerIndex) .parse(false); functionNode.returns = target; functionType.arguments = new DataType[functionTable.arguments.Count]; // TODO: This is the wrong count, I think functionNode.definitionCount = ast.Count - startNodeCount; Token brace = tokens[cursor + 1]; if (brace.type != TT.BRACE_OPEN) { throw Jolly.unexpected(brace); } cursor += 2; // Skip parenthesis close and brace open new ScopeParser(parseData, brace.partnerIndex, functionTable) .parse(ScopeParseMethod.BLOCK); functionNode.memberCount = ast.Count - startNodeCount; terminator = TT.BRACE_CLOSE; // HACK: stop parsing cursor = brace.partnerIndex - 1; } else { // Variable AST_Declaration variableNode; if (defineMode == DefineMode.MEMBER) { var structType = (DataType_Struct)scope.declaration.dType; if (structType.memberMap.ContainsKey(name)) { throw Jolly.addError(token.location, "Type {0} already contains a member named {1}".fill(structType.name, name)); } structType.memberMap.Add(name, structType.memberMap.Count); variableNode = new AST_Declaration(token.location, target, scope, name); } else if ((defineMode & (DefineMode.STATEMENT | DefineMode.ARGUMENT)) != 0) { Symbol variableSymbol = new Symbol(scope); variableNode = new AST_Declaration(token.location, target); variableSymbol.isGeneric = (target.nodeType == NT.TEMPLATE_NAME); //TODO: Fix generic in tuple variableSymbol.defineIndex = defineIndex++; variableNode.symbol = variableSymbol; variableNode.text = name; if (defineMode == DefineMode.ARGUMENT) { ((FunctionTable)scope).arguments.Add(name, variableSymbol); } else { scope.addChild(name, variableSymbol); } } else { throw Jolly.addError(token.location, "Can't define the variable \"{0}\" here.".fill(name)); } prevDefinedType = target; values.Push(variableNode); ast.Add(variableNode); contextStack.Push(new Context(ast.Count, Context.Kind.DECLARATION) { target = variableNode }); } } // parseIdentifier()
static void tupleContext(AST_Node node) => contextStack.Push(new Context(cursor + ((AST_Tuple)node).memberCount, Context.Kind.TUPLE) { target = node });
static void skipSymbol(AST_Node node) => cursor += (node as AST_Scope).memberCount;
public void addValue(AST_Node _value) { prevTokenKind = TokenKind.VALUE; values.Push(_value); }
public AST_FunctionCall(SourceLocation loc, AST_Node f, AST_Node[] a) : base(loc, NT.FUNCTION_CALL) { arguments = a; function = f; }
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()
public static ParseException unexpected(AST_Node node) => addError(node.location, "Unexpected {0}".fill(formatEnum(node.nodeType)));
public AST_Declaration(SourceLocation loc, AST_Node typeFrom, SymbolTable scope, string name) : base(loc, NT.DECLARATION, scope, name) { this.typeFrom = typeFrom; }