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; } }
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})"); }
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)); }
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); }
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); }
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); }
public virtual ReturnType VisitBinaryExpr(AstBinaryExpr expr, DataType data = default) => default;
protected void ResolveBinaryExpr(AstBinaryExpr expr) { ResolveExpr(expr.m_leftExpr); ResolveExpr(expr.m_rightExpr); }
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); }