Optional types and null propagation
This commit is contained in:
@@ -639,10 +639,9 @@ begin
|
||||
else if SameText(head.Token.Text, '?') then
|
||||
begin
|
||||
// (? test1 branch1 test2 branch2 ... else)
|
||||
// Requires odd number of tailNodes (pairs + 1 else)
|
||||
var count := Length(tailNodes);
|
||||
if (count < 1) or ((count mod 2) = 0) then
|
||||
Error('Syntax Error: ''?'' (cond) requires an odd number of arguments (pairs of condition/branch and one final else).');
|
||||
Error('Syntax Error: ''?'' (cond) requires an odd number of arguments.');
|
||||
|
||||
var pairs: TArray<TCondPair>;
|
||||
SetLength(pairs, count div 2);
|
||||
@@ -667,7 +666,7 @@ begin
|
||||
Error('Syntax Error: ''defmacro'' requires a name, a parameter list, and a body.');
|
||||
|
||||
var macroName := tailNodes[0].AsIdentifier;
|
||||
var macroParams := elements[2].Params;
|
||||
var macroParams := elements[2].Params; // Parameter list parsing happens in ParseExpression for brackets
|
||||
|
||||
if tailNodes[2].Kind <> akQuasiquote then
|
||||
Error('Syntax Error: Expected a quasiquote as macro body.');
|
||||
@@ -677,25 +676,68 @@ begin
|
||||
else if SameText(head.Token.Text, 'assign') then
|
||||
begin
|
||||
if Length(tailNodes) <> 2 then
|
||||
Error('Syntax Error: ''assign'' requires exactly 2 arguments (target and value).');
|
||||
Error('Syntax Error: ''assign'' requires exactly 2 arguments.');
|
||||
Result := TAst.Assign(tailNodes[0], tailNodes[1], startLoc);
|
||||
end
|
||||
else if SameText(head.Token.Text, 'fn') then
|
||||
begin
|
||||
if Length(tailNodes) <> 2 then
|
||||
Error('Syntax Error: ''fn'' requires a parameter list and a body.');
|
||||
// elements[1] is the parameter list node which contains the parsed Params array
|
||||
Result := TAst.LambdaExpr(elements[1].Params, tailNodes[1], startLoc);
|
||||
end
|
||||
else if SameText(head.Token.Text, 'do') then
|
||||
begin
|
||||
Result := TAst.Block(tailNodes, startLoc)
|
||||
end
|
||||
else if SameText(head.Token.Text, 'recur') then
|
||||
begin
|
||||
Result := TAst.Recur(tailNodes, startLoc)
|
||||
end
|
||||
else if SameText(head.Token.Text, 'get') then
|
||||
begin
|
||||
if Length(tailNodes) <> 2 then
|
||||
Error('Syntax Error: ''get'' requires exactly 2 arguments (base and index).');
|
||||
Result := TAst.Indexer(tailNodes[0], tailNodes[1], startLoc)
|
||||
end
|
||||
// --- NEW: Support for new-series ---
|
||||
else if SameText(head.Token.Text, 'new-series') then
|
||||
begin
|
||||
if Length(tailNodes) <> 1 then
|
||||
Error('Syntax Error: ''new-series'' requires exactly 1 argument (definition string).');
|
||||
|
||||
// Extract definition string from constant node
|
||||
if (tailNodes[0].Kind = akConstant) and (tailNodes[0].AsConstant.Value.Kind = vkText) then
|
||||
Result := TAst.CreateSeries(tailNodes[0].AsConstant.Value.AsText, startLoc)
|
||||
else
|
||||
Error('Syntax Error: ''new-series'' argument must be a string literal.');
|
||||
end
|
||||
// --- NEW: Support for add-item ---
|
||||
else if SameText(head.Token.Text, 'add-item') then
|
||||
begin
|
||||
if not (Length(tailNodes) in [2, 3]) then
|
||||
Error('Syntax Error: ''add-item'' requires 2 or 3 arguments (series, value, [lookback]).');
|
||||
|
||||
var lookback: IAstNode := nil;
|
||||
if Length(tailNodes) = 3 then
|
||||
lookback := tailNodes[2];
|
||||
|
||||
if tailNodes[0].Kind <> akIdentifier then
|
||||
Error('Syntax Error: ''add-item'' first argument must be a series identifier.');
|
||||
|
||||
Result := TAst.AddSeriesItem(tailNodes[0].AsIdentifier, tailNodes[1], lookback, startLoc);
|
||||
end
|
||||
// --- NEW: Support for count (SeriesLength) ---
|
||||
else if SameText(head.Token.Text, 'count') then
|
||||
begin
|
||||
if Length(tailNodes) <> 1 then
|
||||
Error('Syntax Error: ''count'' requires exactly 1 argument (series).');
|
||||
|
||||
if tailNodes[0].Kind <> akIdentifier then
|
||||
Error('Syntax Error: ''count'' argument must be a series identifier.');
|
||||
|
||||
Result := TAst.SeriesLength(tailNodes[0].AsIdentifier, startLoc);
|
||||
end
|
||||
else if (Length(head.Token.Text) > 1) and (head.Token.Text.StartsWith('.')) then
|
||||
begin
|
||||
if Length(tailNodes) <> 1 then
|
||||
@@ -1136,8 +1178,6 @@ class function TAstScript.Parse(const ASource: string): IAstNode;
|
||||
var
|
||||
p: TParser;
|
||||
begin
|
||||
if ASource.Trim.IsEmpty then
|
||||
exit(nil);
|
||||
p := TParser.Create(ASource);
|
||||
try
|
||||
Result := p.Parse;
|
||||
|
||||
Reference in New Issue
Block a user