Skip to content
26 changes: 25 additions & 1 deletion src/OneScript.Language/LanguageDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,31 @@ public static Token GetToken(string tokText)
public static int GetPriority(Token op)
{
return _priority[op];
}
}

public static int GetBinaryPriority(Token op)
{
return IsBinaryOperator(op) ? _priority[op] : -1;
}

public static int GetUnaryPriority(Token op)
{
return op switch
{
Token.OpenPar => MAX_OPERATION_PRIORITY + 1,

Token.Not => _priority[op],
Token.UnaryMinus => _priority[op],
Token.UnaryPlus => _priority[op],

Token.Minus => _priority[Token.UnaryMinus],
Token.Plus => _priority[Token.UnaryPlus],

_ => MAX_OPERATION_PRIORITY
};
}



[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsBuiltInFunction(Token token)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@ public BinaryOperationNode(Lexem operation) : base(NodeKind.BinaryOperation, ope
{
Operation = operation.Token;
}

public BinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, Lexem operation)
: base(NodeKind.BinaryOperation, operation)
{
Operation = operation.Token;
AddChild(firstArg);
AddChild(secondArg);
}
Comment on lines +21 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same null child concern applies here.

Both firstArg and secondArg can be null when expression parsing fails. The BuildExpression method returns default on syntax errors (line 1290 in DefaultBslParser.cs), which would result in null children being added to the node.

Consider defensive null checks consistent with UnaryOperationNode.

🛡️ Proposed defensive check
 public BinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, Lexem operation)
     : base(NodeKind.BinaryOperation, operation)
 {
     Operation = operation.Token;
-    AddChild(firstArg);
-    AddChild(secondArg);
+    if (firstArg != null)
+        AddChild(firstArg);
+    if (secondArg != null)
+        AddChild(secondArg);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public BinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, Lexem operation)
: base(NodeKind.BinaryOperation, operation)
{
Operation = operation.Token;
AddChild(firstArg);
AddChild(secondArg);
}
public BinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, Lexem operation)
: base(NodeKind.BinaryOperation, operation)
{
Operation = operation.Token;
if (firstArg != null)
AddChild(firstArg);
if (secondArg != null)
AddChild(secondArg);
}
🤖 Prompt for AI Agents
In `@src/OneScript.Language/SyntaxAnalysis/AstNodes/BinaryOperationNode.cs` around
lines 21 - 27, The BinaryOperationNode constructor currently calls
AddChild(firstArg) and AddChild(secondArg) without null checks, which can add
null children when BuildExpression returns default; mirror the defensive pattern
used in UnaryOperationNode by only calling AddChild for firstArg and secondArg
when they are not null (and ensure Operation assignment handles a possibly null
operation safely if needed), so update the BinaryOperationNode constructor to
guard AddChild calls against null children.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public ConditionNode(Lexem startLexem) : base(NodeKind.Condition, startLexem)
public IEnumerable<BslSyntaxNode> GetAlternatives()
{
if(_alternativesStart == 0)
return new BslSyntaxNode[0];
return System.Array.Empty<BslSyntaxNode>();

return Children
.Skip(_alternativesStart)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public LineMarkerNode(CodeRange location, NodeKind kind)
Kind = kind;
}

public override IReadOnlyList<BslSyntaxNode> Children => new BslSyntaxNode[0];
public override IReadOnlyList<BslSyntaxNode> Children => System.Array.Empty<BslSyntaxNode>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public MethodNode() : base(NodeKind.Method)
public IReadOnlyList<VariableDefinitionNode> VariableDefinitions()
{
if (VariableSection == default)
return new VariableDefinitionNode[0];
return System.Array.Empty<VariableDefinitionNode>();

return VariableSection.Children
.Cast<VariableDefinitionNode>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public IEnumerable<MethodParameterNode> GetParameters()
{
var paramList = Children.FirstOrDefault(x => x.Kind == NodeKind.MethodParameters);
if (paramList == default)
return new MethodParameterNode[0];
return System.Array.Empty<MethodParameterNode>();

return ((NonTerminalNode) paramList).Children.Cast<MethodParameterNode>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ public TerminalNode(NodeKind kind, Lexem lexem)
Location = lexem.Location;
}

public override IReadOnlyList<BslSyntaxNode> Children => EmptyChildren;

private static readonly BslSyntaxNode[] EmptyChildren = new BslSyntaxNode[0];
public override IReadOnlyList<BslSyntaxNode> Children => System.Array.Empty<BslSyntaxNode>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ public class UnaryOperationNode : NonTerminalNode
public UnaryOperationNode(Lexem operation) : base(NodeKind.UnaryOperation, operation)
{
Operation = operation.Token;
}
}

public UnaryOperationNode(BslSyntaxNode arg, Lexem operation) : base(NodeKind.UnaryOperation, operation)
{
Operation = operation.Token;
AddChild(arg);
}
Comment on lines +21 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential null child propagation.

The arg parameter could be null when the caller's expression parsing fails (e.g., BuildExpression returns default on line 1290 of DefaultBslParser.cs). Adding a null child may cause issues downstream during AST traversal or code generation.

Consider adding a null guard or ensuring callers handle the error case before constructing the node.

🛡️ Proposed defensive check
 public UnaryOperationNode(BslSyntaxNode arg, Lexem operation) : base(NodeKind.UnaryOperation, operation)
 {
     Operation = operation.Token;
-    AddChild(arg);
+    if (arg != null)
+        AddChild(arg);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public UnaryOperationNode(BslSyntaxNode arg, Lexem operation) : base(NodeKind.UnaryOperation, operation)
{
Operation = operation.Token;
AddChild(arg);
}
public UnaryOperationNode(BslSyntaxNode arg, Lexem operation) : base(NodeKind.UnaryOperation, operation)
{
Operation = operation.Token;
if (arg != null)
AddChild(arg);
}
🤖 Prompt for AI Agents
In `@src/OneScript.Language/SyntaxAnalysis/AstNodes/UnaryOperationNode.cs` around
lines 21 - 25, The UnaryOperationNode constructor can receive a null arg which
then gets passed to AddChild causing downstream failures; update the
UnaryOperationNode(BslSyntaxNode arg, Lexem operation) constructor to
defensively handle a null arg (either by validating and throwing a clear
ArgumentNullException mentioning UnaryOperationNode/arg, or by skipping AddChild
when arg is null and setting a safe placeholder), and ensure Operation is still
set from operation.Token; reference the UnaryOperationNode constructor, the arg
parameter, the Operation property, and the AddChild method when making the
change.

}
}
Loading