Keywords
This commit is contained in:
@@ -694,6 +694,7 @@ begin
|
|||||||
result := ExecuteAst(root, fibScope);
|
result := ExecuteAst(root, fibScope);
|
||||||
sw.Stop;
|
sw.Stop;
|
||||||
Memo1.Lines.Add(Format('Result: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
Memo1.Lines.Add(Format('Result: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
||||||
|
|
||||||
UpdateScript;
|
UpdateScript;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -920,7 +921,7 @@ begin
|
|||||||
[
|
[
|
||||||
TAst.VarDecl(
|
TAst.VarDecl(
|
||||||
TAst.Identifier('closeSeries'),
|
TAst.Identifier('closeSeries'),
|
||||||
TAst.MemberAccess(TAst.Identifier('ohlcv'), TAst.Identifier('Close'))
|
TAst.MemberAccess(TAst.Identifier('ohlcv'), TAst.Keyword('Close'))
|
||||||
),
|
),
|
||||||
TAst.VarDecl(
|
TAst.VarDecl(
|
||||||
TAst.Identifier('currentClose'),
|
TAst.Identifier('currentClose'),
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ uses
|
|||||||
FMX.StdCtrls,
|
FMX.StdCtrls,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
|
Myc.Data.Keyword,
|
||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Visitor,
|
Myc.Ast.Visitor,
|
||||||
Myc.Ast,
|
Myc.Ast,
|
||||||
@@ -478,7 +479,7 @@ type
|
|||||||
TAuraRecordLiteralNode = class(TAuraNode)
|
TAuraRecordLiteralNode = class(TAuraNode)
|
||||||
private
|
private
|
||||||
FNode: IRecordLiteralNode;
|
FNode: IRecordLiteralNode;
|
||||||
FFieldNodes: TDictionary<string, TAuraNode>; // Map KeyName -> ValueNode
|
FFieldNodes: TDictionary<IKeyword, TAuraNode>; // Map KeyName -> ValueNode
|
||||||
protected
|
protected
|
||||||
procedure SetupNode; override;
|
procedure SetupNode; override;
|
||||||
public
|
public
|
||||||
@@ -525,9 +526,6 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
|
||||||
Myc.Data.Keyword;
|
|
||||||
|
|
||||||
{ TAstVisualizer }
|
{ TAstVisualizer }
|
||||||
|
|
||||||
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer);
|
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer);
|
||||||
@@ -2032,7 +2030,7 @@ end;
|
|||||||
function TAuraMemberAccessNode.CreateAst: IAstNode;
|
function TAuraMemberAccessNode.CreateAst: IAstNode;
|
||||||
begin
|
begin
|
||||||
// Re-create identifier from FNode
|
// Re-create identifier from FNode
|
||||||
Result := TAst.MemberAccess(FBaseNode.CreateAst, TAst.Identifier(FNode.Member.Name));
|
Result := TAst.MemberAccess(FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Value.Name));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAuraMemberAccessNode.SetupNode;
|
procedure TAuraMemberAccessNode.SetupNode;
|
||||||
@@ -2049,7 +2047,7 @@ begin
|
|||||||
AddLabel(Self, '.');
|
AddLabel(Self, '.');
|
||||||
|
|
||||||
// Add member name as a label
|
// Add member name as a label
|
||||||
AddLabel(Self, FNode.Member.Name);
|
AddLabel(Self, FNode.Member.Value.Name);
|
||||||
finally
|
finally
|
||||||
EndUpdate;
|
EndUpdate;
|
||||||
end;
|
end;
|
||||||
@@ -2061,7 +2059,7 @@ constructor TAuraRecordLiteralNode.Create(const AVisualizer: IAstVisualizer; con
|
|||||||
begin
|
begin
|
||||||
inherited Create(AVisualizer);
|
inherited Create(AVisualizer);
|
||||||
FNode := ANode;
|
FNode := ANode;
|
||||||
FFieldNodes := TDictionary<string, TAuraNode>.Create;
|
FFieldNodes := TDictionary<IKeyword, TAuraNode>.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TAuraRecordLiteralNode.Destroy;
|
destructor TAuraRecordLiteralNode.Destroy;
|
||||||
@@ -2075,7 +2073,7 @@ var
|
|||||||
fields: TArray<TRecordFieldLiteral>;
|
fields: TArray<TRecordFieldLiteral>;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
valueNode: TAuraNode;
|
valueNode: TAuraNode;
|
||||||
pair: TPair<string, TAuraNode>;
|
pair: TPair<IKeyword, TAuraNode>;
|
||||||
begin
|
begin
|
||||||
SetLength(fields, FFieldNodes.Count);
|
SetLength(fields, FFieldNodes.Count);
|
||||||
i := 0;
|
i := 0;
|
||||||
@@ -2084,7 +2082,7 @@ begin
|
|||||||
for pair in FFieldNodes do
|
for pair in FFieldNodes do
|
||||||
begin
|
begin
|
||||||
valueNode := pair.Value;
|
valueNode := pair.Value;
|
||||||
fields[i] := TRecordFieldLiteral.Create(pair.Key, valueNode.CreateAst);
|
fields[i] := TRecordFieldLiteral.Create(TKeywordNode.Create(pair.Key), valueNode.CreateAst);
|
||||||
inc(i);
|
inc(i);
|
||||||
end;
|
end;
|
||||||
Result := TAst.RecordLiteral(fields);
|
Result := TAst.RecordLiteral(fields);
|
||||||
@@ -2115,7 +2113,7 @@ begin
|
|||||||
fieldContainer := AddContainer(Self, loHorizontal, laCenter);
|
fieldContainer := AddContainer(Self, loHorizontal, laCenter);
|
||||||
|
|
||||||
// Key label
|
// Key label
|
||||||
keyLabel := AddLabel(fieldContainer, ':' + field.Name);
|
keyLabel := AddLabel(fieldContainer, ':' + field.Key.Value.Name);
|
||||||
keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold];
|
keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold];
|
||||||
keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor];
|
keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor];
|
||||||
keyLabel.FontColor := TAlphaColors.Mediumvioletred;
|
keyLabel.FontColor := TAlphaColors.Mediumvioletred;
|
||||||
@@ -2124,7 +2122,7 @@ begin
|
|||||||
valueNode := FVisualizer.Clone(fieldContainer, FVisualizer.ExprDepth + 1).CallAccept(field.Value);
|
valueNode := FVisualizer.Clone(fieldContainer, FVisualizer.ExprDepth + 1).CallAccept(field.Value);
|
||||||
|
|
||||||
// Store for CreateAst
|
// Store for CreateAst
|
||||||
FFieldNodes.Add(field.Name, valueNode);
|
FFieldNodes.Add(field.Key.Value, valueNode);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ var
|
|||||||
baseStr: string;
|
baseStr: string;
|
||||||
begin
|
begin
|
||||||
baseStr := Node.Base.Accept(Self).AsText;
|
baseStr := Node.Base.Accept(Self).AsText;
|
||||||
Result := Format('%s.%s', [baseStr, Node.Member.Name]);
|
Result := Format('%s.%s', [baseStr, Node.Member.Value.Name]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstToTextVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
function TAstToTextVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
||||||
|
|||||||
+30
-19
@@ -259,8 +259,15 @@ begin
|
|||||||
// externally evaluate the expression using the injected evaluator
|
// externally evaluate the expression using the injected evaluator
|
||||||
value := FEvaluate(expr);
|
value := FEvaluate(expr);
|
||||||
|
|
||||||
|
// Allow unquoting keywords
|
||||||
if value.Kind in [vkScalar, vkText, vkVoid, vkKeyword] then
|
if value.Kind in [vkScalar, vkText, vkVoid, vkKeyword] then
|
||||||
Result := TDataValue.FromIntf<IAstNode>(TAst.Constant(value))
|
begin
|
||||||
|
// vkKeyword needs to be handled differently than other constants
|
||||||
|
if value.Kind = vkKeyword then
|
||||||
|
Result := TDataValue.FromIntf<IAstNode>(TAst.Keyword(value.AsKeyword.Name))
|
||||||
|
else
|
||||||
|
Result := TDataValue.FromIntf<IAstNode>(TAst.Constant(value));
|
||||||
|
end
|
||||||
else
|
else
|
||||||
raise Exception.CreateFmt('Cannot unquote complex value of type %s at compile time.', [value.Kind.ToString]);
|
raise Exception.CreateFmt('Cannot unquote complex value of type %s at compile time.', [value.Kind.ToString]);
|
||||||
end;
|
end;
|
||||||
@@ -290,8 +297,8 @@ end;
|
|||||||
|
|
||||||
function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
// This node type does not support splicing, so we use the default
|
// Record literals do not support splicing.
|
||||||
// TAstTransformer implementation which just transforms child values.
|
// We just use the default TAstTransformer implementation which visits child values.
|
||||||
Result := inherited VisitRecordLiteral(Node);
|
Result := inherited VisitRecordLiteral(Node);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -500,6 +507,7 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
// --- Transformation: Keyword-as-Function ---
|
// --- Transformation: Keyword-as-Function ---
|
||||||
|
// Check if the callee is a keyword literal
|
||||||
if (Node.Callee is TKeywordNode) then
|
if (Node.Callee is TKeywordNode) then
|
||||||
begin
|
begin
|
||||||
var keywordNode := (Node.Callee as TKeywordNode);
|
var keywordNode := (Node.Callee as TKeywordNode);
|
||||||
@@ -508,18 +516,17 @@ begin
|
|||||||
// 1. Validate argument count
|
// 1. Validate argument count
|
||||||
if Length(Node.Arguments) <> 1 then
|
if Length(Node.Arguments) <> 1 then
|
||||||
raise ETypeException
|
raise ETypeException
|
||||||
.CreateFmt('Keyword :%s expects exactly one argument (the record), but got %d', [keywordName, Length(Node.Arguments)]);
|
.CreateFmt('Keyword :%s expects exactly one argument (the record/map), but got %d', [keywordName, Length(Node.Arguments)]);
|
||||||
|
|
||||||
// 2. Bind the base (the record)
|
// 2. Bind the base (the record/map)
|
||||||
FNextIsTail := False; // Accessing a member is not a tail call
|
FNextIsTail := False; // Accessing a member is not a tail call
|
||||||
var baseNode := Accept(Node.Arguments[0]).AsIntf<IAstNode>;
|
var baseNode := Accept(Node.Arguments[0]).AsIntf<IAstNode>;
|
||||||
|
|
||||||
// 3. Create a synthetic IMemberAccessNode
|
// 3. Create a synthetic IMemberAccessNode
|
||||||
var memberIdentifier := TAst.Identifier(keywordName);
|
var memberAccessNode := TAst.MemberAccess(baseNode, TAst.Keyword(keywordName));
|
||||||
var memberAccessNode := TAst.MemberAccess(baseNode, memberIdentifier);
|
|
||||||
|
|
||||||
// 4. Re-bind the synthetic node by calling Accept (which dispatches to VisitMemberAccess)
|
// 4. Re-bind the synthetic node by calling Accept (which dispatches to VisitMemberAccess)
|
||||||
// This ensures type checking and type inference for member access is done in one place.
|
// This ensures type checking and type inference for member access is centralized.
|
||||||
Result := Accept(memberAccessNode);
|
Result := Accept(memberAccessNode);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@@ -925,19 +932,19 @@ var
|
|||||||
begin
|
begin
|
||||||
baseNode := Accept(Node.Base).AsIntf<IAstNode>;
|
baseNode := Accept(Node.Base).AsIntf<IAstNode>;
|
||||||
baseType := (baseNode as TAstNode).StaticType;
|
baseType := (baseNode as TAstNode).StaticType;
|
||||||
var memberName := Node.Member.Name;
|
|
||||||
|
|
||||||
elemType := TTypes.Unknown;
|
elemType := TTypes.Unknown;
|
||||||
if (baseType.Kind <> TStaticTypeKind.stUnknown) then
|
if (baseType.Kind <> TStaticTypeKind.stUnknown) then
|
||||||
begin
|
begin
|
||||||
if (baseType.Kind <> TStaticTypeKind.stRecord) and (baseType.Kind <> TStaticTypeKind.stRecordSeries) then
|
if (baseType.Kind <> TStaticTypeKind.stRecord) and (baseType.Kind <> TStaticTypeKind.stRecordSeries) then
|
||||||
raise ETypeException.CreateFmt('Member access `.` requires a record or record series, but got %s', [baseType.ToString]);
|
raise ETypeException.CreateFmt('Member access requires a record or record series, but got %s', [baseType.ToString]);
|
||||||
|
|
||||||
fieldIndex := baseType.Definition.IndexOf(memberName);
|
// Use IndexOf(string) which correctly delegates to IndexOf(IKeyword)
|
||||||
|
fieldIndex := baseType.Definition.IndexOf(Node.Member.Value);
|
||||||
if fieldIndex < 0 then
|
if fieldIndex < 0 then
|
||||||
raise ETypeException.CreateFmt('Member "%s" not found in type %s', [memberName, baseType.ToString]);
|
raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]);
|
||||||
|
|
||||||
var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Kind);
|
var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Value);
|
||||||
|
|
||||||
if baseType.Kind = TStaticTypeKind.stRecord then
|
if baseType.Kind = TStaticTypeKind.stRecord then
|
||||||
elemType := fieldType
|
elemType := fieldType
|
||||||
@@ -953,7 +960,7 @@ function TAstBinder.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataVal
|
|||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
boundFields: TArray<TRecordFieldLiteral>;
|
boundFields: TArray<TRecordFieldLiteral>;
|
||||||
defFields: TArray<TScalarRecordField>;
|
defFields: TArray<TScalarRecordDefinition.TField>;
|
||||||
def: TScalarRecordDefinition;
|
def: TScalarRecordDefinition;
|
||||||
staticType: IStaticType;
|
staticType: IStaticType;
|
||||||
boundNode: IRecordLiteralNode;
|
boundNode: IRecordLiteralNode;
|
||||||
@@ -964,18 +971,21 @@ begin
|
|||||||
SetLength(boundFields, Length(Node.Fields));
|
SetLength(boundFields, Length(Node.Fields));
|
||||||
SetLength(defFields, Length(Node.Fields));
|
SetLength(defFields, Length(Node.Fields));
|
||||||
|
|
||||||
|
// We assume this is a TScalarRecord (Path A) until proven otherwise.
|
||||||
|
// The "dual path" logic for stDictionary is not yet implemented.
|
||||||
|
|
||||||
for i := 0 to High(Node.Fields) do
|
for i := 0 to High(Node.Fields) do
|
||||||
begin
|
begin
|
||||||
valNode := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
valNode := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
||||||
valType := (valNode as TAstNode).StaticType;
|
valType := (valNode as TAstNode).StaticType;
|
||||||
|
|
||||||
// Records can only store scalar values
|
// Path A: Records can only store scalar values
|
||||||
if not (valType.Kind in [stOrdinal, stFloat]) then
|
if not (valType.Kind in [stOrdinal, stFloat]) then
|
||||||
raise ETypeException.CreateFmt(
|
raise ETypeException.CreateFmt(
|
||||||
'Record fields must be scalar (Ordinal or Float), but field "%s" is %s',
|
'Record fields must be scalar (Ordinal or Float), but field ":%s" is %s',
|
||||||
[Node.Fields[i].Name, valType.ToString]);
|
[Node.Fields[i].Key.Value.Name, valType.ToString]);
|
||||||
|
|
||||||
boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Name, valNode);
|
boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Key, valNode);
|
||||||
|
|
||||||
var scalarKind: TScalar.TKind;
|
var scalarKind: TScalar.TKind;
|
||||||
if valType.Kind = stOrdinal then
|
if valType.Kind = stOrdinal then
|
||||||
@@ -983,7 +993,8 @@ begin
|
|||||||
else
|
else
|
||||||
scalarKind := TScalar.TKind.Float;
|
scalarKind := TScalar.TKind.Float;
|
||||||
|
|
||||||
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Name, scalarKind);
|
// Create the definition field using the Keyword's name
|
||||||
|
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
def := TScalarRecordDefinition.Create(defFields);
|
def := TScalarRecordDefinition.Create(defFields);
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ end;
|
|||||||
|
|
||||||
function TDebugEvaluatorVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
function TDebugEvaluatorVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
AppendLine(Format('MemberAccess (Member: %s) {', [Node.Member.Name]));
|
AppendLine(Format('MemberAccess (Member: %s) {', [Node.Member.Value.Name]));
|
||||||
Indent;
|
Indent;
|
||||||
try
|
try
|
||||||
Result := inherited VisitMemberAccess(Node);
|
Result := inherited VisitMemberAccess(Node);
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ begin
|
|||||||
Indent;
|
Indent;
|
||||||
for field in Node.Fields do
|
for field in Node.Fields do
|
||||||
begin
|
begin
|
||||||
LogFmt('Field :%s', [field.Name]);
|
LogFmt('Field :%s', [field.Key.Value.Name]);
|
||||||
Indent;
|
Indent;
|
||||||
field.Value.Accept(Self);
|
field.Value.Accept(Self);
|
||||||
Unindent;
|
Unindent;
|
||||||
|
|||||||
@@ -437,14 +437,12 @@ end;
|
|||||||
function TEvaluatorVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
function TEvaluatorVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||||
var
|
var
|
||||||
baseValue: TDataValue;
|
baseValue: TDataValue;
|
||||||
memberName: string;
|
|
||||||
begin
|
begin
|
||||||
baseValue := Node.Base.Accept(Self);
|
baseValue := Node.Base.Accept(Self);
|
||||||
memberName := Node.Member.Name;
|
|
||||||
|
|
||||||
case baseValue.Kind of
|
case baseValue.Kind of
|
||||||
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries.CreateMemberSeries(memberName));
|
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries.CreateMemberSeries(Node.Member.Value));
|
||||||
vkRecord: Result := baseValue.AsRecord.Items[memberName];
|
vkRecord: Result := baseValue.AsRecord[Node.Member.Value];
|
||||||
else
|
else
|
||||||
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
|
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ begin
|
|||||||
field.Value.Accept(Self); // This pushes the value JSON onto the stack
|
field.Value.Accept(Self); // This pushes the value JSON onto the stack
|
||||||
|
|
||||||
fieldObj := TJSONObject.Create;
|
fieldObj := TJSONObject.Create;
|
||||||
fieldObj.AddPair('Name', TJSONString.Create(field.Name));
|
fieldObj.AddPair('Name', TJSONString.Create(field.Key.Value.Name));
|
||||||
fieldObj.AddPair('Value', FJsonObjectStack.Pop);
|
fieldObj.AddPair('Value', FJsonObjectStack.Pop);
|
||||||
fieldsArray.Add(fieldObj);
|
fieldsArray.Add(fieldObj);
|
||||||
end;
|
end;
|
||||||
@@ -900,7 +900,7 @@ end;
|
|||||||
|
|
||||||
function TJsonAstConverter.JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
|
function TJsonAstConverter.JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
|
||||||
begin
|
begin
|
||||||
Result := TAst.MemberAccess(JsonToNode(AObj.GetValue('Base')), JsonToIdentifierNode(AObj.GetValue('Member') as TJSONObject));
|
Result := TAst.MemberAccess(JsonToNode(AObj.GetValue('Base')), JsonToKeywordNode(AObj.GetValue('Member') as TJSONObject));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
|
function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
|
||||||
@@ -915,7 +915,11 @@ begin
|
|||||||
for i := 0 to fieldsArray.Count - 1 do
|
for i := 0 to fieldsArray.Count - 1 do
|
||||||
begin
|
begin
|
||||||
fieldObj := fieldsArray.Items[i] as TJSONObject;
|
fieldObj := fieldsArray.Items[i] as TJSONObject;
|
||||||
fields[i] := TRecordFieldLiteral.Create(fieldObj.GetValue<string>('Name'), JsonToNode(fieldObj.GetValue('Value')));
|
fields[i] :=
|
||||||
|
TRecordFieldLiteral.Create(
|
||||||
|
TKeywordNode.Create(TKeywordRegistry.Intern(fieldObj.GetValue<string>('Name'))),
|
||||||
|
JsonToNode(fieldObj.GetValue('Value'))
|
||||||
|
);
|
||||||
end;
|
end;
|
||||||
Result := TAst.RecordLiteral(fields);
|
Result := TAst.RecordLiteral(fields);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ type
|
|||||||
|
|
||||||
// A single field in a record literal
|
// A single field in a record literal
|
||||||
TRecordFieldLiteral = record
|
TRecordFieldLiteral = record
|
||||||
Name: string; // The field name (from keyword :name)
|
Key: IKeywordNode;
|
||||||
Value: IAstNode;
|
Value: IAstNode;
|
||||||
constructor Create(const AName: string; const AValue: IAstNode);
|
constructor Create(const AKey: IKeywordNode; const AValue: IAstNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
IAstVisitor = interface
|
IAstVisitor = interface
|
||||||
@@ -264,10 +264,10 @@ type
|
|||||||
IMemberAccessNode = interface(IAstNode)
|
IMemberAccessNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetBase: IAstNode;
|
function GetBase: IAstNode;
|
||||||
function GetMember: IIdentifierNode;
|
function GetMember: IKeywordNode;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
property Base: IAstNode read GetBase;
|
property Base: IAstNode read GetBase;
|
||||||
property Member: IIdentifierNode read GetMember;
|
property Member: IKeywordNode read GetMember;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Represents a record literal, e.g., {:a 1 :b 2}
|
// Represents a record literal, e.g., {:a 1 :b 2}
|
||||||
@@ -335,9 +335,9 @@ end;
|
|||||||
|
|
||||||
{ TRecordFieldLiteral }
|
{ TRecordFieldLiteral }
|
||||||
|
|
||||||
constructor TRecordFieldLiteral.Create(const AName: string; const AValue: IAstNode);
|
constructor TRecordFieldLiteral.Create(const AKey: IKeywordNode; const AValue: IAstNode);
|
||||||
begin
|
begin
|
||||||
Name := AName;
|
Key := AKey;
|
||||||
Value := AValue;
|
Value := AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ begin
|
|||||||
raise Exception.Create('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
|
raise Exception.Create('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
|
||||||
fieldValue := ParseExpression.Node;
|
fieldValue := ParseExpression.Node;
|
||||||
|
|
||||||
fields.Add(TRecordFieldLiteral.Create(fieldName, fieldValue));
|
fields.Add(TRecordFieldLiteral.Create(TKeywordNode.Create(TKeywordRegistry.Intern(fieldName)), fieldValue));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := TAst.RecordLiteral(fields.ToArray);
|
Result := TAst.RecordLiteral(fields.ToArray);
|
||||||
@@ -490,7 +490,7 @@ begin
|
|||||||
else if SameText(head.Token.Text, 'get') then
|
else if SameText(head.Token.Text, 'get') then
|
||||||
Result := TAst.Indexer(tailNodes[0], tailNodes[1])
|
Result := TAst.Indexer(tailNodes[0], tailNodes[1])
|
||||||
else if (Length(head.Token.Text) > 1) and (head.Token.Text.StartsWith('.')) then
|
else if (Length(head.Token.Text) > 1) and (head.Token.Text.StartsWith('.')) then
|
||||||
Result := TAst.MemberAccess(tailNodes[0], TAst.Identifier(head.Token.Text.Substring(1)));
|
Result := TAst.MemberAccess(tailNodes[0], TAst.Keyword(head.Token.Text.Substring(1)));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// If no special form matched, treat it as a generic function call.
|
// If no special form matched, treat it as a generic function call.
|
||||||
@@ -916,7 +916,7 @@ begin
|
|||||||
for field in Node.Fields do
|
for field in Node.Fields do
|
||||||
begin
|
begin
|
||||||
NewLine;
|
NewLine;
|
||||||
Append(':' + field.Name);
|
Append(':' + field.Key.Value.Name);
|
||||||
Append(' ');
|
Append(' ');
|
||||||
field.Value.Accept(Self);
|
field.Value.Accept(Self);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -386,7 +386,8 @@ begin
|
|||||||
|
|
||||||
for i := 0 to High(Self.FDefinition.Fields) do
|
for i := 0 to High(Self.FDefinition.Fields) do
|
||||||
begin
|
begin
|
||||||
if (Self.FDefinition.Fields[i].Name <> otherDef.Fields[i].Name) or (Self.FDefinition.Fields[i].Kind <> otherDef.Fields[i].Kind) then
|
// Use fast interface comparison for Keys
|
||||||
|
if (Self.FDefinition.Fields[i].Key <> otherDef.Fields[i].Key) or (Self.FDefinition.Fields[i].Value <> otherDef.Fields[i].Value) then
|
||||||
exit(False);
|
exit(False);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -400,7 +401,7 @@ begin
|
|||||||
Result := GetKind.ToString + '{';
|
Result := GetKind.ToString + '{';
|
||||||
for i := 0 to High(FDefinition.Fields) do
|
for i := 0 to High(FDefinition.Fields) do
|
||||||
begin
|
begin
|
||||||
Result := Result + FDefinition.Fields[i].Name + ': ' + FDefinition.Fields[i].Kind.ToString;
|
Result := Result + FDefinition.Fields[i].Key.Name + ': ' + FDefinition.Fields[i].Value.ToString;
|
||||||
if i < High(FDefinition.Fields) then
|
if i < High(FDefinition.Fields) then
|
||||||
Result := Result + ', ';
|
Result := Result + ', ';
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ end;
|
|||||||
function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
var base := Accept(Node.Base).AsIntf<IAstNode>;
|
var base := Accept(Node.Base).AsIntf<IAstNode>;
|
||||||
var member := Node.Member;
|
var member := Accept(Node.Member).AsIntf<IKeywordNode>;
|
||||||
if (base = Node.Base) and (member = Node.Member) then
|
if (base = Node.Base) and (member = Node.Member) then
|
||||||
Result := TDataValue.FromIntf<IMemberAccessNode>(Node)
|
Result := TDataValue.FromIntf<IMemberAccessNode>(Node)
|
||||||
else
|
else
|
||||||
@@ -331,6 +331,7 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
hasChanged: Boolean;
|
hasChanged: Boolean;
|
||||||
newFields: TArray<TRecordFieldLiteral>;
|
newFields: TArray<TRecordFieldLiteral>;
|
||||||
|
newKey: IKeywordNode;
|
||||||
newValue: IAstNode;
|
newValue: IAstNode;
|
||||||
begin
|
begin
|
||||||
hasChanged := False;
|
hasChanged := False;
|
||||||
@@ -338,10 +339,13 @@ begin
|
|||||||
|
|
||||||
for i := 0 to High(Node.Fields) do
|
for i := 0 to High(Node.Fields) do
|
||||||
begin
|
begin
|
||||||
|
newKey := Accept(Node.Fields[i].Key).AsIntf<IKeywordNode>;
|
||||||
newValue := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
newValue := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
||||||
if newValue <> Node.Fields[i].Value then
|
|
||||||
|
if (newKey <> Node.Fields[i].Key) or (newValue <> Node.Fields[i].Value) then
|
||||||
hasChanged := True;
|
hasChanged := True;
|
||||||
newFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Name, newValue);
|
|
||||||
|
newFields[i] := TRecordFieldLiteral.Create(newKey, newValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if hasChanged then
|
if hasChanged then
|
||||||
|
|||||||
+15
-13
@@ -58,7 +58,7 @@ type
|
|||||||
class function Assign(const AIdentifier: IIdentifierNode; const AValue: IAstNode): IAssignmentNode; static;
|
class function Assign(const AIdentifier: IIdentifierNode; const AValue: IAstNode): IAssignmentNode; static;
|
||||||
class function AssignResult(const AValue: IAstNode): IAssignmentNode; static; deprecated;
|
class function AssignResult(const AValue: IAstNode): IAssignmentNode; static; deprecated;
|
||||||
class function Indexer(const ABase: IAstNode; const AIndex: IAstNode): IIndexerNode; static;
|
class function Indexer(const ABase: IAstNode; const AIndex: IAstNode): IIndexerNode; static;
|
||||||
class function MemberAccess(const ABase: IAstNode; const AMember: IIdentifierNode): IMemberAccessNode; static;
|
class function MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode): IMemberAccessNode; static;
|
||||||
class function RecordLiteral(const AFields: TArray<TRecordFieldLiteral>): IRecordLiteralNode; static;
|
class function RecordLiteral(const AFields: TArray<TRecordFieldLiteral>): IRecordLiteralNode; static;
|
||||||
class function CreateSeries(const ADefinition: String): ICreateSeriesNode; static;
|
class function CreateSeries(const ADefinition: String): ICreateSeriesNode; static;
|
||||||
class function AddSeriesItem(
|
class function AddSeriesItem(
|
||||||
@@ -104,7 +104,7 @@ type
|
|||||||
FValue: IKeyword;
|
FValue: IKeyword;
|
||||||
function GetValue: IKeyword;
|
function GetValue: IKeyword;
|
||||||
public
|
public
|
||||||
constructor Create(const AName: string);
|
constructor Create(const AValue: IKeyword);
|
||||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
property Value: IKeyword read FValue;
|
property Value: IKeyword read FValue;
|
||||||
end;
|
end;
|
||||||
@@ -292,11 +292,11 @@ type
|
|||||||
TMemberAccessNode = class(TAstNode, IMemberAccessNode)
|
TMemberAccessNode = class(TAstNode, IMemberAccessNode)
|
||||||
private
|
private
|
||||||
FBase: IAstNode;
|
FBase: IAstNode;
|
||||||
FMember: IIdentifierNode;
|
FMember: IKeywordNode;
|
||||||
function GetBase: IAstNode;
|
function GetBase: IAstNode;
|
||||||
function GetMember: IIdentifierNode;
|
function GetMember: IKeywordNode;
|
||||||
public
|
public
|
||||||
constructor Create(const ABase: IAstNode; const AMember: IIdentifierNode);
|
constructor Create(const ABase: IAstNode; const AMember: IKeywordNode);
|
||||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -349,14 +349,15 @@ constructor TConstantNode.Create(const AValue: TDataValue);
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
// Validate that only allowed constant kinds are used.
|
// Validate that only allowed constant kinds are used.
|
||||||
if not (AValue.Kind in [vkScalar, vkText, vkVoid]) then
|
if not (AValue.Kind in [vkScalar, vkText, vkVoid, vkKeyword]) then
|
||||||
raise EArgumentException.Create('IConstantNode only supports Scalar, Text, and Void values.');
|
raise EArgumentException.Create('IConstantNode only supports Scalar, Text, Void and Keyword values.');
|
||||||
FValue := AValue;
|
FValue := AValue;
|
||||||
|
|
||||||
case AValue.Kind of
|
case AValue.Kind of
|
||||||
vkScalar: StaticType := TTypes.FromScalarKind(AValue.AsScalar.Kind);
|
vkScalar: StaticType := TTypes.FromScalarKind(AValue.AsScalar.Kind);
|
||||||
vkText: StaticType := TTypes.Text;
|
vkText: StaticType := TTypes.Text;
|
||||||
vkVoid: StaticType := TTypes.Void;
|
vkVoid: StaticType := TTypes.Void;
|
||||||
|
vkKeyword: StaticType := TTypes.Keyword;
|
||||||
else
|
else
|
||||||
StaticType := TTypes.Unknown; // Should not happen due to validation above
|
StaticType := TTypes.Unknown; // Should not happen due to validation above
|
||||||
end;
|
end;
|
||||||
@@ -392,11 +393,12 @@ end;
|
|||||||
|
|
||||||
{ TKeywordNode }
|
{ TKeywordNode }
|
||||||
|
|
||||||
constructor TKeywordNode.Create(const AName: string);
|
constructor TKeywordNode.Create(const AValue: IKeyword);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FValue := TKeywordRegistry.Intern(AName);
|
FValue := AValue;
|
||||||
StaticType := TTypes.Keyword;
|
StaticType := TTypes.Keyword;
|
||||||
|
FValue := AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TKeywordNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
function TKeywordNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||||
@@ -788,7 +790,7 @@ end;
|
|||||||
|
|
||||||
{ TMemberAccessNode }
|
{ TMemberAccessNode }
|
||||||
|
|
||||||
constructor TMemberAccessNode.Create(const ABase: IAstNode; const AMember: IIdentifierNode);
|
constructor TMemberAccessNode.Create(const ABase: IAstNode; const AMember: IKeywordNode);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FBase := ABase;
|
FBase := ABase;
|
||||||
@@ -805,7 +807,7 @@ begin
|
|||||||
Result := FBase;
|
Result := FBase;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TMemberAccessNode.GetMember: IIdentifierNode;
|
function TMemberAccessNode.GetMember: IKeywordNode;
|
||||||
begin
|
begin
|
||||||
Result := FMember;
|
Result := FMember;
|
||||||
end;
|
end;
|
||||||
@@ -992,7 +994,7 @@ end;
|
|||||||
|
|
||||||
class function TAst.Keyword(const AName: string): IKeywordNode;
|
class function TAst.Keyword(const AName: string): IKeywordNode;
|
||||||
begin
|
begin
|
||||||
Result := TKeywordNode.Create(AName);
|
Result := TKeywordNode.Create(TKeywordRegistry.Intern(AName));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
||||||
@@ -1009,7 +1011,7 @@ begin
|
|||||||
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody);
|
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IIdentifierNode): IMemberAccessNode;
|
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode): IMemberAccessNode;
|
||||||
begin
|
begin
|
||||||
Result := TMemberAccessNode.Create(ABase, AMember);
|
Result := TMemberAccessNode.Create(ABase, AMember);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ uses
|
|||||||
type
|
type
|
||||||
// The runtime representation of an interned keyword
|
// The runtime representation of an interned keyword
|
||||||
IKeyword = interface(IInterface)
|
IKeyword = interface(IInterface)
|
||||||
|
function GetIdx: Integer;
|
||||||
function GetName: string;
|
function GetName: string;
|
||||||
|
property Idx: Integer read GetIdx;
|
||||||
property Name: string read GetName;
|
property Name: string read GetName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -22,9 +24,11 @@ type
|
|||||||
TKeyword = class(TInterfacedObject, IKeyword)
|
TKeyword = class(TInterfacedObject, IKeyword)
|
||||||
private
|
private
|
||||||
FName: string;
|
FName: string;
|
||||||
|
FIdx: Integer;
|
||||||
function GetName: string;
|
function GetName: string;
|
||||||
|
function GetIdx: Integer;
|
||||||
public
|
public
|
||||||
constructor Create(const AName: string);
|
constructor Create(const AName: string; AIdx: Integer);
|
||||||
end;
|
end;
|
||||||
strict private
|
strict private
|
||||||
class var
|
class var
|
||||||
@@ -38,14 +42,38 @@ type
|
|||||||
class function Intern(const AName: string): IKeyword; static;
|
class function Intern(const AName: string): IKeyword; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TKeywordMapping<T> = record
|
||||||
|
type
|
||||||
|
TField = record
|
||||||
|
Key: IKeyword;
|
||||||
|
Value: T;
|
||||||
|
public
|
||||||
|
constructor Create(const AKey: IKeyword; const AValue: T);
|
||||||
|
end;
|
||||||
|
private
|
||||||
|
FMap: TArray<Integer>;
|
||||||
|
FFields: TArray<TField>;
|
||||||
|
FFirst, FLast: Integer;
|
||||||
|
public
|
||||||
|
constructor Create(const AFields: TArray<TField>);
|
||||||
|
function IndexOf(const Key: IKeyword): Integer;
|
||||||
|
property Fields: TArray<TField> read FFields;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TKeywordRegistry.TKeyword }
|
{ TKeywordRegistry.TKeyword }
|
||||||
|
|
||||||
constructor TKeywordRegistry.TKeyword.Create(const AName: string);
|
constructor TKeywordRegistry.TKeyword.Create(const AName: string; AIdx: Integer);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FName := AName;
|
FName := AName;
|
||||||
|
FIdx := AIdx;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TKeywordRegistry.TKeyword.GetIdx: Integer;
|
||||||
|
begin
|
||||||
|
Result := FIdx;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TKeywordRegistry.TKeyword.GetName: string;
|
function TKeywordRegistry.TKeyword.GetName: string;
|
||||||
@@ -72,7 +100,7 @@ begin
|
|||||||
try
|
try
|
||||||
if not FRegistry.TryGetValue(AName, Result) then
|
if not FRegistry.TryGetValue(AName, Result) then
|
||||||
begin
|
begin
|
||||||
Result := TKeyword.Create(AName);
|
Result := TKeyword.Create(AName, FRegistry.Count);
|
||||||
FRegistry.Add(AName, Result);
|
FRegistry.Add(AName, Result);
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
@@ -80,4 +108,47 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TKeywordMapping }
|
||||||
|
|
||||||
|
constructor TKeywordMapping<T>.Create(const AFields: TArray<TField>);
|
||||||
|
begin
|
||||||
|
FFields := AFields;
|
||||||
|
FFirst := 0;
|
||||||
|
FLast := -1;
|
||||||
|
if Length(FFields) = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
FFirst := FFields[0].Key.Idx;
|
||||||
|
FLast := FFirst;
|
||||||
|
for var i := 1 to High(FFields) do
|
||||||
|
begin
|
||||||
|
var idx := FFields[i].Key.Idx;
|
||||||
|
if FFirst > idx then
|
||||||
|
FFirst := idx;
|
||||||
|
if FLast < idx then
|
||||||
|
FLast := idx;
|
||||||
|
end;
|
||||||
|
|
||||||
|
SetLength(FMap, FLast - FFirst + 1);
|
||||||
|
for var i := 0 to High(FMap) do
|
||||||
|
FMap[i] := -1;
|
||||||
|
for var i := 0 to High(FFields) do
|
||||||
|
FMap[FFirst + FFields[i].Key.Idx] := i;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TKeywordMapping<T>.IndexOf(const Key: IKeyword): Integer;
|
||||||
|
begin
|
||||||
|
var idx := Key.Idx - FFirst;
|
||||||
|
if (idx < 0) or (Idx > High(FMap)) then
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
Result := FMap[idx];
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TKeywordMapping<T>.TField.Create(const AKey: IKeyword; const AValue: T);
|
||||||
|
begin
|
||||||
|
Key := AKey;
|
||||||
|
Value := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
System.Generics.Collections,
|
||||||
Myc.Data.Decimal,
|
Myc.Data.Decimal,
|
||||||
System.Generics.Collections;
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
{ TRttiAstHelper }
|
{ TRttiAstHelper }
|
||||||
|
|
||||||
@@ -35,7 +36,8 @@ var
|
|||||||
fieldsArray: TJSONArray;
|
fieldsArray: TJSONArray;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
fieldObj: TJSONObject;
|
fieldObj: TJSONObject;
|
||||||
kindStr: string;
|
kindStr, fieldName: string;
|
||||||
|
fieldKey: IKeyword;
|
||||||
fields: TArray<TScalarRecordField>;
|
fields: TArray<TScalarRecordField>;
|
||||||
begin
|
begin
|
||||||
jsonValue := TJSONObject.ParseJSONValue(AJson);
|
jsonValue := TJSONObject.ParseJSONValue(AJson);
|
||||||
@@ -55,9 +57,11 @@ begin
|
|||||||
if not Assigned(fieldObj) then
|
if not Assigned(fieldObj) then
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fields[i].Name := fieldObj.GetValue<string>('name');
|
fieldName := fieldObj.GetValue<string>('name');
|
||||||
|
fieldKey := TKeywordRegistry.Intern(fieldName);
|
||||||
kindStr := fieldObj.GetValue<string>('kind');
|
kindStr := fieldObj.GetValue<string>('kind');
|
||||||
fields[i].Kind := TScalar.TKind(GetEnumValue(TypeInfo(TScalar.TKind), kindStr));
|
|
||||||
|
fields[i] := TScalarRecordField.Create(fieldKey, TScalar.TKind(GetEnumValue(TypeInfo(TScalar.TKind), kindStr)));
|
||||||
end;
|
end;
|
||||||
Result := TScalarRecordDefinition.Create(fields);
|
Result := TScalarRecordDefinition.Create(fields);
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ interface
|
|||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
Myc.Data.Decimal,
|
Myc.Data.Decimal,
|
||||||
Myc.Data.Series;
|
Myc.Data.Series,
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
{$SCOPEDENUMS ON}
|
{$SCOPEDENUMS ON}
|
||||||
|
|
||||||
@@ -91,20 +92,8 @@ type
|
|||||||
TScalarTuple = TArray<TScalar>;
|
TScalarTuple = TArray<TScalar>;
|
||||||
|
|
||||||
// A field definition for a scalar record.
|
// A field definition for a scalar record.
|
||||||
TScalarRecordField = record
|
TScalarRecordField = TKeywordMapping<TScalar.TKind>.TField;
|
||||||
Name: String;
|
TScalarRecordDefinition = TKeywordMapping<TScalar.TKind>;
|
||||||
Kind: TScalar.TKind;
|
|
||||||
constructor Create(const AName: String; AKind: TScalar.TKind);
|
|
||||||
end;
|
|
||||||
|
|
||||||
TScalarRecordDefinition = record
|
|
||||||
private
|
|
||||||
FFields: TArray<TScalarRecordField>;
|
|
||||||
public
|
|
||||||
constructor Create(const AFields: TArray<TScalarRecordField>);
|
|
||||||
function IndexOf(const Name: String): Integer;
|
|
||||||
property Fields: TArray<TScalarRecordField> read FFields;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// A record of scalar values, based on a definition.
|
// A record of scalar values, based on a definition.
|
||||||
TScalarRecord = record
|
TScalarRecord = record
|
||||||
@@ -112,10 +101,10 @@ type
|
|||||||
constructor Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
constructor Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
||||||
function GetDef: TScalarRecordDefinition; inline;
|
function GetDef: TScalarRecordDefinition; inline;
|
||||||
function GetFields: TArray<TScalar.TValue>; inline;
|
function GetFields: TArray<TScalar.TValue>; inline;
|
||||||
function GetItems(const Name: String): TScalar;
|
function GetKeys(const Key: IKeyword): TScalar;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Def: TScalarRecordDefinition read GetDef;
|
||||||
property Fields: TArray<TScalar.TValue> read GetFields;
|
property Fields: TArray<TScalar.TValue> read GetFields;
|
||||||
property Items[const Name: String]: TScalar read GetItems; default;
|
property Keys[const Key: IKeyword]: TScalar read GetKeys; default;
|
||||||
strict private
|
strict private
|
||||||
FDef: TScalarRecordDefinition;
|
FDef: TScalarRecordDefinition;
|
||||||
FFields: TArray<TScalar.TValue>;
|
FFields: TArray<TScalar.TValue>;
|
||||||
@@ -158,7 +147,7 @@ type
|
|||||||
function GetTotalCount: Int64;
|
function GetTotalCount: Int64;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
||||||
function CreateMemberSeries(const Field: String): ISeries;
|
function CreateMemberSeries(const Key: IKeyword): ISeries;
|
||||||
property Count: Int64 read GetCount;
|
property Count: Int64 read GetCount;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Def: TScalarRecordDefinition read GetDef;
|
||||||
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
||||||
@@ -192,7 +181,7 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(const ADef: TScalarRecordDefinition);
|
constructor Create(const ADef: TScalarRecordDefinition);
|
||||||
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
||||||
function CreateMemberSeries(const Field: String): ISeries;
|
function CreateMemberSeries(const Key: IKeyword): ISeries;
|
||||||
property Count: Int64 read GetCount;
|
property Count: Int64 read GetCount;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Def: TScalarRecordDefinition read GetDef;
|
||||||
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
||||||
@@ -528,14 +517,6 @@ begin
|
|||||||
Items := AItems;
|
Items := AItems;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TScalarRecordField }
|
|
||||||
|
|
||||||
constructor TScalarRecordField.Create(const AName: String; AKind: TScalar.TKind);
|
|
||||||
begin
|
|
||||||
Name := AName;
|
|
||||||
Kind := AKind;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TScalarRecord }
|
{ TScalarRecord }
|
||||||
|
|
||||||
constructor TScalarRecord.Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
constructor TScalarRecord.Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
||||||
@@ -555,34 +536,15 @@ begin
|
|||||||
Result := FFields;
|
Result := FFields;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecord.GetItems(const Name: String): TScalar;
|
function TScalarRecord.GetKeys(const Key: IKeyword): TScalar;
|
||||||
var
|
var
|
||||||
idx: Integer;
|
idx: Integer;
|
||||||
begin
|
begin
|
||||||
idx := FDef.IndexOf(Name);
|
idx := FDef.IndexOf(Key);
|
||||||
if idx < 0 then
|
if idx < 0 then
|
||||||
raise EArgumentException.CreateFmt('Field "%s" not found in record definition.', [Name]);
|
raise EArgumentException.CreateFmt('Field ":%s" not found in record definition.', [Key.Name]);
|
||||||
|
|
||||||
Result.Create(FDef.Fields[idx].Kind, FFields[idx]);
|
Result.Create(FDef.Fields[idx].Value, FFields[idx]);
|
||||||
end;
|
|
||||||
|
|
||||||
{ TScalarRecordDefinition }
|
|
||||||
|
|
||||||
constructor TScalarRecordDefinition.Create(const AFields: TArray<TScalarRecordField>);
|
|
||||||
begin
|
|
||||||
FFields := AFields;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TScalarRecordDefinition.IndexOf(const Name: String): Integer;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
for i := 0 to High(FFields) do
|
|
||||||
begin
|
|
||||||
if (CompareText(FFields[i].Name, Name) = 0) then
|
|
||||||
exit(i);
|
|
||||||
end;
|
|
||||||
Result := -1;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TScalarRecordSeries }
|
{ TScalarRecordSeries }
|
||||||
@@ -600,11 +562,11 @@ begin
|
|||||||
inc(FTotalCount);
|
inc(FTotalCount);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecordSeries.CreateMemberSeries(const Field: String): ISeries;
|
function TScalarRecordSeries.CreateMemberSeries(const Key: IKeyword): ISeries;
|
||||||
begin
|
begin
|
||||||
var elem := FDef.IndexOf(Field);
|
var elem := FDef.IndexOf(Key);
|
||||||
if elem < 0 then
|
if elem < 0 then
|
||||||
raise EArgumentException.CreateFmt('Field "%s" not found in record definition.', [Field]);
|
raise EArgumentException.CreateFmt('Field ":%s" not found in record definition.', [Key.Name]);
|
||||||
|
|
||||||
Result := TMemberSeries.Create(Self, elem);
|
Result := TMemberSeries.Create(Self, elem);
|
||||||
end;
|
end;
|
||||||
@@ -686,7 +648,7 @@ begin
|
|||||||
inherited Create;
|
inherited Create;
|
||||||
FRecordSeries := ARecordSeries;
|
FRecordSeries := ARecordSeries;
|
||||||
FRecordSeries._AddRef;
|
FRecordSeries._AddRef;
|
||||||
FKind := FRecordSeries.FDef.FFields[AElementIdx].Kind;
|
FKind := FRecordSeries.FDef.Fields[AElementIdx].Value;
|
||||||
FOffset := sizeof(TScalar.TValue) * AElementIdx;
|
FOffset := sizeof(TScalar.TValue) * AElementIdx;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@@ -82,12 +82,12 @@ type
|
|||||||
class function FromRecordSeries(const AValue: IRecordSeries): TDataValue; static; inline;
|
class function FromRecordSeries(const AValue: IRecordSeries): TDataValue; static; inline;
|
||||||
class function FromRecord(const [ref] AValue: TScalarRecord): TDataValue; static; inline;
|
class function FromRecord(const [ref] AValue: TScalarRecord): TDataValue; static; inline;
|
||||||
class function FromSeries(const AValue: ISeries): TDataValue; static; inline;
|
class function FromSeries(const AValue: ISeries): TDataValue; static; inline;
|
||||||
class function FromKeyword(const AValue: IKeyword): TDataValue; static; inline; // Added
|
class function FromKeyword(const AValue: IKeyword): TDataValue; static; inline;
|
||||||
|
|
||||||
function AsScalar: TScalar; inline;
|
function AsScalar: TScalar; inline;
|
||||||
function AsMethod: TFunc; inline;
|
function AsMethod: TFunc; inline;
|
||||||
function AsText: String; inline;
|
function AsText: String; inline;
|
||||||
function AsKeyword: IKeyword; inline; // Added
|
function AsKeyword: IKeyword; inline;
|
||||||
function AsRecordSeries: IRecordSeries; inline;
|
function AsRecordSeries: IRecordSeries; inline;
|
||||||
function AsRecord: TScalarRecord; inline;
|
function AsRecord: TScalarRecord; inline;
|
||||||
function AsSeries: ISeries; inline;
|
function AsSeries: ISeries; inline;
|
||||||
@@ -264,7 +264,7 @@ begin
|
|||||||
TInterlocked.CompareExchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64, Expected.AsScalar.Value.AsInt64)
|
TInterlocked.CompareExchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64, Expected.AsScalar.Value.AsInt64)
|
||||||
= Expected.AsScalar.Value.AsInt64;
|
= Expected.AsScalar.Value.AsInt64;
|
||||||
|
|
||||||
vkText, vkKeyword, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric: // Added vkKeyword
|
vkText, vkKeyword, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric:
|
||||||
Result := IntfCompareExchange(FInterface, NewValue.FInterface, Expected.FInterface) = Expected.FInterface;
|
Result := IntfCompareExchange(FInterface, NewValue.FInterface, Expected.FInterface) = Expected.FInterface;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -369,7 +369,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
vkPointer: Result := TInterlocked.Exchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64);
|
vkPointer: Result := TInterlocked.Exchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64);
|
||||||
|
|
||||||
vkText, vkKeyword, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric: // Added vkKeyword
|
vkText, vkKeyword, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric:
|
||||||
begin
|
begin
|
||||||
Result.FKind := FKind;
|
Result.FKind := FKind;
|
||||||
Result.FInterface := IntfExchange(FInterface, NewValue.FInterface);
|
Result.FInterface := IntfExchange(FInterface, NewValue.FInterface);
|
||||||
@@ -386,7 +386,7 @@ begin
|
|||||||
case FKind of
|
case FKind of
|
||||||
vkScalar: Result := FScalar.ToString;
|
vkScalar: Result := FScalar.ToString;
|
||||||
vkText: Result := '"' + AsText + '"';
|
vkText: Result := '"' + AsText + '"';
|
||||||
vkKeyword: Result := ':' + AsKeyword.Name; // Added
|
vkKeyword: Result := ':' + AsKeyword.Name;
|
||||||
vkSeries:
|
vkSeries:
|
||||||
begin
|
begin
|
||||||
var series := AsSeries;
|
var series := AsSeries;
|
||||||
@@ -404,7 +404,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if not first then
|
if not first then
|
||||||
sb.Append(',');
|
sb.Append(',');
|
||||||
sb.Append(field.Name);
|
sb.Append(field.Key.Name);
|
||||||
first := False;
|
first := False;
|
||||||
end;
|
end;
|
||||||
sb.Append('}');
|
sb.Append('}');
|
||||||
@@ -425,7 +425,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if not first then
|
if not first then
|
||||||
sb.Append(',');
|
sb.Append(',');
|
||||||
sb.Append(field.Name);
|
sb.Append(field.Key.Name);
|
||||||
first := False;
|
first := False;
|
||||||
end;
|
end;
|
||||||
sb.Append('}');
|
sb.Append('}');
|
||||||
@@ -490,7 +490,7 @@ begin
|
|||||||
vkVoid: Result := 'Void';
|
vkVoid: Result := 'Void';
|
||||||
vkScalar: Result := 'Scalar';
|
vkScalar: Result := 'Scalar';
|
||||||
vkText: Result := 'Text';
|
vkText: Result := 'Text';
|
||||||
vkKeyword: Result := 'Keyword'; // Added
|
vkKeyword: Result := 'Keyword';
|
||||||
vkSeries: Result := 'Series';
|
vkSeries: Result := 'Series';
|
||||||
vkRecordSeries: Result := 'RecordSeries';
|
vkRecordSeries: Result := 'RecordSeries';
|
||||||
vkRecord: Result := 'Record';
|
vkRecord: Result := 'Record';
|
||||||
|
|||||||
Reference in New Issue
Block a user