Beispiel #1
0
 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;
 }
Beispiel #2
0
        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;
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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;
        }
Beispiel #5
0
        } // 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
            });
        }
Beispiel #6
0
 public Enclosure(NT t, AST_Node n, SymbolTable s, int e)
 {
     scope = s;
     type  = t;
     node  = n;
     end   = e;
 }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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();
            }
        }
Beispiel #9
0
        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
                });
            }
        }
Beispiel #10
0
        } // 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()
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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
            });
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        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));
        }
Beispiel #17
0
        /*###########
        *   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);
        }
Beispiel #18
0
        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
            });
        }
Beispiel #19
0
        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
            });
        }
Beispiel #20
0
        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
            });
        }
Beispiel #21
0
        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);
            }
        }
Beispiel #22
0
        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()
Beispiel #23
0
        } // 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()
Beispiel #24
0
 static void tupleContext(AST_Node node)
 => contextStack.Push(new Context(cursor + ((AST_Tuple)node).memberCount, Context.Kind.TUPLE)
 {
     target = node
 });
Beispiel #25
0
 static void skipSymbol(AST_Node node)
 => cursor += (node as AST_Scope).memberCount;
Beispiel #26
0
 public void addValue(AST_Node _value)
 {
     prevTokenKind = TokenKind.VALUE;
     values.Push(_value);
 }
Beispiel #27
0
 public AST_FunctionCall(SourceLocation loc, AST_Node f, AST_Node[] a)
     : base(loc, NT.FUNCTION_CALL)
 {
     arguments = a; function = f;
 }
Beispiel #28
0
        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()
Beispiel #29
0
 public static ParseException unexpected(AST_Node node)
 => addError(node.location, "Unexpected {0}".fill(formatEnum(node.nodeType)));
Beispiel #30
0
 public AST_Declaration(SourceLocation loc, AST_Node typeFrom, SymbolTable scope, string name)
     : base(loc, NT.DECLARATION, scope, name)
 {
     this.typeFrom = typeFrom;
 }