Prexonite, a .NET hosted scripting language with a focus on meta-programming and embedded DSLs
0

Configure Feed

Select the types of activity you want to include in your feed.

PRX-36: Error message for incomplete binary expr

This PR introduces a more explicit error message for parsing errors where one of the operands of a binary expression end up missing.

This fixes an internal compiler error (`ArgumentNullException` when parsing `(?*)`)

Christian Klauser (Apr 28, 2021, 12:34 PM +0200) 2ab7b207 5e7bcf90

+57 -2
+41 -2
Prexonite/Compiler/AST/AstFactoryBase.cs
··· 222 222 concatenation._OptimizeInternal(CompileTimeExecutionContext); 223 223 } 224 224 225 + /// <summary> 226 + /// Report errors if either of the operands are <c>null</c>. 227 + /// </summary> 228 + /// <remarks> 229 + /// We do this in a separate method because <see cref="BinaryOperation"/> is annotated with non-null 230 + /// annotations, but there is one caller, the parser, for which it is impractical to have null checking enabled. 231 + /// </remarks> 232 + /// <returns><c>true</c> if the operands are valid; <c>false</c> otherwise</returns> 233 + private bool validateBinaryOperands(ISourcePosition position, [CanBeNull] AstExpr left, 234 + BinaryOperator op, [CanBeNull] AstExpr right) 235 + { 236 + var isValid = true; 237 + if (left == null) 238 + { 239 + ReportMessage(Message.Create( 240 + MessageSeverity.Error, 241 + string.Format(Resources.Parser_BinaryOperandMissing_Left, op), 242 + position, 243 + MessageClasses.IncompleteBinaryOperation)); 244 + isValid = false; 245 + } 246 + if (right == null) 247 + { 248 + ReportMessage(Message.Create( 249 + MessageSeverity.Error, 250 + string.Format(Resources.Parser_BinaryOperandMissing_Right, op), 251 + position, 252 + MessageClasses.IncompleteBinaryOperation)); 253 + isValid = false; 254 + } 255 + 256 + return isValid; 257 + } 258 + 225 259 public AstExpr BinaryOperation(ISourcePosition position, AstExpr left, BinaryOperator op, AstExpr right) 226 260 { 261 + if (!validateBinaryOperands(position, left, op, right)) 262 + { 263 + return IndirectCall(position, Null(position)); 264 + } 265 + 227 266 PValue leftNeutral = null; 228 267 PValue rightNeutral = null; 229 268 switch (op) ··· 269 308 // If the LH- or RHS was a concatenation, the concatenation variable is set. 270 309 // Applying other transformations would be wrong. 271 310 // "text" + 0 == "text0" 272 - // We don't want to ellide the addition of 0 here, even though 0 is the neutral element of addition. 311 + // We don't want to elide the addition of 0 here, even though 0 is the neutral element of addition. 273 312 if (concatenation != null) 274 313 { 275 314 _foldConcatenation(concatenation); ··· 345 384 case BinaryOperator.Coalescence: 346 385 return Coalescence(position, new[] {left, right}); 347 386 case BinaryOperator.Cast: 348 - if (!(right is AstTypeExpr T)) 387 + if (right is not AstTypeExpr T) 349 388 { 350 389 ReportMessage(Message.Error(Resources.AstFactoryBase_BinaryOperation_TypeExprExpected, 351 390 position, MessageClasses.TypeExpressionExpected));
+1
Prexonite/Compiler/MessageClasses.cs
··· 63 63 public const string QualifiedIdPartsAfterWildcard = "P.QualifiedIdPartsAfterWildcard"; 64 64 public const string NonTopLevelNamespaceImport = "P.NonTopLevelNamespaceImport"; 65 65 public const string UnexpectedDoubleColonInNamespaceName = "P.UnexpectedDoubleColonInNamespaceName"; 66 + public const string IncompleteBinaryOperation = "P.IncompleteBinaryOperation"; 66 67 67 68 #endregion 68 69
+6
Prexonite/Properties/Resources.resx
··· 439 439 <data name="Parser_DoubleColonInNamespaceName" xml:space="preserve"> 440 440 <value>Double colon (`::`) not allowed in namespace name.</value> 441 441 </data> 442 + <data name="Parser_BinaryOperandMissing_Left" xml:space="preserve"> 443 + <value>Left-hand side of {0} operation is missing.</value> 444 + </data> 445 + <data name="Parser_BinaryOperandMissing_Right" xml:space="preserve"> 446 + <value>Right-hand side of {0} operation is missing.</value> 447 + </data> 442 448 </root>
+9
PrexoniteTests/Tests/Translation.cs
··· 1472 1472 Assert.That(ldr.ErrorCount, Is.EqualTo(1), "Error count"); 1473 1473 } 1474 1474 1475 + [Test] 1476 + public void QuestionMarkSpliceIsInvalid() 1477 + { 1478 + var ldr = CompileInvalid(@" 1479 + function main = println(?*); 1480 + "); 1481 + Assert.That(ldr.Errors.Where(m => m.MessageClass == MessageClasses.IncompleteBinaryOperation), Is.Not.Empty); 1482 + } 1483 + 1475 1484 [ContractAnnotation("value:null=>halt")] 1476 1485 private static void _assumeNotNull(object value) 1477 1486 {