Exemplo n.º 1
0
    public static string PrintExpr(AstExpr astRoot)
    {
        switch (astRoot.m_exprk)
        {
        case EXPRK.Binary:
        {
            AstBinaryExpr expr = (AstBinaryExpr)astRoot;
            return("( " + expr.m_tokenkOp.ToString() + " " + PrintExpr(expr.m_leftExpr) + " " + PrintExpr(expr.m_rightExpr) + " )");
        } break;

        case EXPRK.Group:
        {
            AstGroupExpr group = (AstGroupExpr)astRoot;
            return("( " + PrintExpr(group.m_expr) + " )");
        } break;

        case EXPRK.Literal:
        {
            AstLiteralExpr expr = (AstLiteralExpr)astRoot;
            return(expr.m_value.ToString());
        } break;

        case EXPRK.Unary:
        {
            AstUnaryExpr expr = (AstUnaryExpr)astRoot;
            return("( " + expr.m_tokenkOp.ToString() + " " + PrintExpr(expr.m_expr) + " )");
        } break;

        default:
        {
            Debug.Fail("Print not implemented for Ast Node type: " + astRoot.m_astnodek);
            return("<error>");
        } break;
        }
    }
Exemplo n.º 2
0
        public override string VisitBinaryExpr(AstBinaryExpr bin, int data = 0)
        {
            var left  = bin.Left.Accept(this, 0);
            var right = bin.Right.Accept(this, 0);

            return($"({left} {bin.Operator} {right})");
        }
Exemplo n.º 3
0
        public override NodeFinderResult VisitBinaryExpr(AstBinaryExpr bin, int index = 0)
        {
            if (GetRelativeLocation(bin.Left.Location, index) == RelativeLocation.Same)
            {
                return(bin.Left.Accept(this, index));
            }

            if (GetRelativeLocation(bin.Right.Location, index) == RelativeLocation.Same)
            {
                return(bin.Right.Accept(this, index));
            }

            return(new NodeFinderResult(bin.Scope, expr: bin));
        }
Exemplo n.º 4
0
    protected AstExpr ParseMultiplicationExpr()
    {
        AstExpr expr = ParseUnaryExpr();

        if (expr == null)
        {
            return(EmptyErrorExpr());
        }

        Token token;

        while ((token = TryMatch(TOKENK.Star, TOKENK.Slash)) != null)
        {
            AstExpr exprRight = ParseUnaryExpr();
            if (exprRight == null)
            {
                return(EmptyErrorExpr());
            }

            expr = new AstBinaryExpr(expr, token.m_tokenk, exprRight);
        }

        return(expr);
    }
Exemplo n.º 5
0
    protected AstExpr ParseComparisonExpr()
    {
        AstExpr expr = ParseAdditionExpr();

        if (expr == null)
        {
            return(EmptyErrorExpr());
        }

        Token token;

        while ((token = TryMatch(TOKENK.Greater, TOKENK.GreaterEqual, TOKENK.Lesser, TOKENK.LesserEqual)) != null)
        {
            AstExpr exprRight = ParseAdditionExpr();
            if (exprRight == null)
            {
                return(EmptyErrorExpr());
            }

            expr = new AstBinaryExpr(expr, token.m_tokenk, exprRight);
        }

        return(expr);
    }
Exemplo n.º 6
0
    protected object EvaluateBinaryExpr(AstBinaryExpr expr)
    {
        if (HadErrorOrReturn())
        {
            return(null);
        }

        object lValue = EvaluateExpr(expr.m_leftExpr);

        // Test the logical operators first so we can short circuit w/o evaluating rhs

        switch (expr.m_tokenkOp)
        {
        case TOKENK.Or:
        {
            if (IsTruthy(lValue))
            {
                return(lValue);
            }

            object rVal = EvaluateExpr(expr.m_rightExpr);
            return(rVal);
        } break;

        case TOKENK.And:
        {
            if (!IsTruthy(lValue))
            {
                return(lValue);
            }

            object rVal = EvaluateExpr(expr.m_rightExpr);
            return(rVal);
        } break;
        }

        object rValue = EvaluateExpr(expr.m_rightExpr);

        double?lNum = lValue as double?;
        double?rNum = rValue as double?;

        switch (expr.m_tokenkOp)
        {
        case TOKENK.Minus:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value - rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'-' only supported for numbers");
        } break;

        case TOKENK.Slash:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                if (rNum.Value == 0)
                {
                    m_runtimeError = true;
                    Lox.Error(expr.m_startLine, "Divide by 0 error");
                    return(null);
                }

                return(lNum.Value / rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'/' only supported for numbers");
        } break;

        case TOKENK.Star:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value * rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'*' only supported for numbers");
        } break;

        case TOKENK.Plus:
        {
            string lStr = lValue as string;
            string rStr = rValue as string;

            if ((lStr == null && !lNum.HasValue) || (rStr == null && !rNum.HasValue))
            {
                m_runtimeError = true;
                Lox.Error(expr.m_startLine, "'+' only supported for numbers and strings");
            }
            else
            {
                if (lNum.HasValue && rNum.HasValue)
                {
                    return(lNum.Value + rNum.Value);
                }

                if (lStr != null)
                {
                    if (rStr != null)
                    {
                        return(lStr + rStr);
                    }

                    Debug.Assert(rNum.HasValue);

                    return(lStr + rNum.Value);
                }

                Debug.Assert(rStr != null);
                Debug.Assert(lNum.HasValue);

                return(lNum.Value + rStr);
            }
        } break;

        case TOKENK.EqualEqual:
        {
            return(IsEqual(lValue, rValue));
        } break;

        case TOKENK.BangEqual:
        {
            return(IsEqual(lValue, rValue));
        } break;

        // TODO: support lexically comparing strings?

        case TOKENK.Lesser:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value < rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'<' only supported for numbers");
        } break;

        case TOKENK.Greater:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value > rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'>' only supported for numbers");
        } break;

        case TOKENK.LesserEqual:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value <= rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'<=' only supported for numbers");
        } break;

        case TOKENK.GreaterEqual:
        {
            if (lNum.HasValue && rNum.HasValue)
            {
                return(lNum.Value >= rNum.Value);
            }

            m_runtimeError = true;
            Lox.Error(expr.m_startLine, "'>=' only supported for numbers");
        } break;

        default:
        {
            m_runtimeError = true;
            Lox.InternalError(expr.m_startLine, "Binary expression has unexpected operator: " + expr.m_tokenkOp);
        } break;
        }

        Debug.Assert(m_runtimeError);
        return(null);
    }
Exemplo n.º 7
0
 public virtual ReturnType VisitBinaryExpr(AstBinaryExpr expr, DataType data           = default) => default;
Exemplo n.º 8
0
 protected void ResolveBinaryExpr(AstBinaryExpr expr)
 {
     ResolveExpr(expr.m_leftExpr);
     ResolveExpr(expr.m_rightExpr);
 }
Exemplo n.º 9
0
        private AstExpression MatchPatternWithExpression(AstAssignment ass, AstExpression pattern, AstExpression value)
        {
            // check for operator set[]
            if (ass.Pattern is AstArrayAccessExpr arr)
            {
                // before we search for operators, make sure that all impls for both arguments have been matched
                GetImplsForType(arr.SubExpression.Type);
                GetImplsForType(arr.Arguments[0].Type);
                GetImplsForType(value.Type);

                var ops = ass.Scope.GetNaryOperators("set[]", arr.SubExpression.Type, arr.Arguments[0].Type, value.Type);
                if (ops.Count == 0)
                {
                    var type = arr.SubExpression.Type;
                    if (type is ReferenceType r)
                    {
                        type = r.TargetType;
                    }
                    else
                    {
                        type = ReferenceType.GetRefType(type, true);
                    }
                    ops = ass.Scope.GetNaryOperators("set[]", type, arr.Arguments[0].Type, value.Type);
                }

                if (ops.Count == 0)
                {
                    if (!pattern.TypeInferred)
                    {
                        pattern.SetFlag(ExprFlags.AssignmentTarget, false);
                        ass.Pattern = pattern = InferType(pattern, null);
                    }
                }
                else if (ops.Count == 1)
                {
                    arr.SubExpression = HandleReference(arr.SubExpression, ops[0].ArgTypes[0], null);
                    var args = new List <AstExpression>
                    {
                        arr.SubExpression,
                        arr.Arguments[0],
                        value
                    };
                    var opCall = new AstNaryOpExpr("set[]", args, value.Location);
                    opCall.ActualOperator = ops[0];
                    opCall.Replace(value);
                    ass.OnlyGenerateValue = true;
                    return(InferType(opCall, null));
                }
                else
                {
                    ReportError(ass, $"Multiple operators 'set[]' match the types ({arr.SubExpression.Type}, {arr.Arguments[0].Type}, {value.Type})");
                }
            }

            if (ass.Operator != null)
            {
                var assOp   = ass.Operator + "=";
                var valType = LiteralTypeToDefaultType(value.Type);

                // before we search for operators, make sure that all impls for both arguments have been matched
                GetImplsForType(pattern.Type);
                GetImplsForType(valType);

                var ops = ass.Scope.GetBinaryOperators(assOp, pattern.Type, valType);
                if (ops.Count == 0)
                {
                    var type = pattern.Type;
                    if (type is ReferenceType r)
                    {
                        type = r.TargetType;
                    }
                    else
                    {
                        type = ReferenceType.GetRefType(type, true);
                    }
                    ops = ass.Scope.GetBinaryOperators(assOp, type, valType);
                }

                if (ops.Count == 1)
                {
                    ass.OnlyGenerateValue = true;
                    pattern = HandleReference(pattern, ops[0].LhsType, null);
                    var opCall = new AstBinaryExpr(assOp, pattern, value, value.Location);
                    opCall.Replace(value);
                    return(InferType(opCall, null));
                }
                else if (ops.Count > 1)
                {
                    ReportError(ass, $"Multiple operators '{assOp}' match the types {PointerType.GetPointerType(pattern.Type, true)} and {value.Type}");
                }
            }

            switch (pattern)
            {
            case AstIdExpr id:
            {
                if (!id.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{id}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);

                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);

                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {ass.Value.Type} to a pattern of type {ass.Pattern.Type}"));
            }

            case AstTupleExpr t:
            {
                if (value is AstTupleExpr v)
                {
                    if (t.Values.Count != v.Values.Count)
                    {
                        ReportError(ass, $"Can't assign the tuple '{v}' to the pattern '{t}' because the amount of values does not match");
                        return(value);
                    }

                    // create new assignments for all sub values
                    for (int i = 0; i < t.Values.Count; i++)
                    {
                        var subPat = t.Values[i];
                        var subVal = v.Values[i];
                        var subAss = new AstAssignment(subPat, subVal, ass.Operator, ass.Location);
                        subAss.Scope = ass.Scope;
                        subAss.Value = MatchPatternWithExpression(subAss, subPat, subVal);
                        ass.AddSubAssignment(subAss);
                    }
                }
                else
                {
                    var tmp = new AstTempVarExpr(value);
                    tmp.SetFlag(ExprFlags.IsLValue, true);

                    // create new assignments for all sub values
                    for (int i = 0; i < t.Values.Count; i++)
                    {
                        AstExpression subVal = new AstArrayAccessExpr(tmp, new AstNumberExpr(i));
                        subVal.Scope = ass.Scope;
                        subVal       = InferType(subVal, t.Values[i].Type);

                        var subAss = new AstAssignment(t.Values[i], subVal, ass.Operator, ass.Location);
                        subAss.Scope = ass.Scope;
                        subAss.Value = MatchPatternWithExpression(subAss, t.Values[i], subVal);
                        ass.AddSubAssignment(subAss);
                    }
                }
                break;
            }

            case AstDereferenceExpr de:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    if (!de.SubExpression.GetFlag(ExprFlags.IsLValue))
                    {
                        AstExpression tmp = new AstTempVarExpr(de.SubExpression);
                        tmp.SetFlag(ExprFlags.IsLValue, true);
                        tmp = InferType(tmp, de.SubExpression.Type);

                        de.SubExpression = tmp;
                    }

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstDotExpr dot:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression tmp = new AstTempVarExpr(dot.Left, true);
                    tmp.SetFlag(ExprFlags.IsLValue, true);
                    //tmp = new AstDereferenceExpr(tmp, tmp.Location);
                    tmp = InferType(tmp, dot.Left.Type);

                    dot.Left = tmp;

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstArrayAccessExpr index:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression tmp = new AstTempVarExpr(index.SubExpression, true);
                    tmp.SetFlag(ExprFlags.IsLValue, true);
                    tmp = InferType(tmp, index.SubExpression.Type);

                    index.SubExpression = tmp;

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstExpression e when e.Type is ReferenceType r:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                // TODO: check if can be assigned to id (e.g. not const)
                if (ass.Operator != null)
                {
                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);
                return(CheckType(ass.Value, r.TargetType, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            default: ReportError(pattern, $"Can't assign to '{pattern.Type}', not an lvalue"); break;
            }

            return(value);
        }