Keywords
This commit is contained in:
+102
-1
@@ -24,6 +24,7 @@ uses
|
||||
System.Math,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Data.Keyword,
|
||||
Myc.Ast;
|
||||
|
||||
type
|
||||
@@ -35,11 +36,14 @@ type
|
||||
tkRightParen, // )
|
||||
tkLeftBracket, // [
|
||||
tkRightBracket, // ]
|
||||
tkLeftBrace, // {
|
||||
tkRightBrace, // }
|
||||
tkQuote, // '
|
||||
tkBacktick, // `
|
||||
tkTilde, // ~
|
||||
tkAt, // @
|
||||
tkIdentifier,
|
||||
tkKeyword,
|
||||
tkNumber,
|
||||
tkString,
|
||||
tkEOF,
|
||||
@@ -82,6 +86,7 @@ type
|
||||
procedure Consume(AExpectedKind: TTokenKind);
|
||||
procedure NextToken;
|
||||
function ParseList: IAstNode;
|
||||
function ParseRecordLiteral: IAstNode;
|
||||
function ParseParameterList: TArray<IIdentifierNode>;
|
||||
function ParseExpression: TExpr;
|
||||
public
|
||||
@@ -108,6 +113,7 @@ type
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
@@ -124,6 +130,7 @@ type
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
@@ -158,7 +165,7 @@ var
|
||||
begin
|
||||
startPos := FCurrentPos;
|
||||
// Reader macro characters are now also delimiters for identifiers.
|
||||
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '''', '`', '~']))) do
|
||||
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '{', '}', '''', '`', '~']))) do
|
||||
Advance;
|
||||
Result := Copy(FSource, startPos, FCurrentPos - startPos);
|
||||
end;
|
||||
@@ -237,6 +244,16 @@ begin
|
||||
Result.Kind := tkRightBracket;
|
||||
Advance;
|
||||
end;
|
||||
'{':
|
||||
begin
|
||||
Result.Kind := tkLeftBrace;
|
||||
Advance;
|
||||
end;
|
||||
'}':
|
||||
begin
|
||||
Result.Kind := tkRightBrace;
|
||||
Advance;
|
||||
end;
|
||||
'''':
|
||||
begin
|
||||
Result.Kind := tkQuote;
|
||||
@@ -262,6 +279,14 @@ begin
|
||||
Result.Kind := tkString;
|
||||
Result.Text := ReadString;
|
||||
end;
|
||||
':':
|
||||
begin
|
||||
Advance; // Skip :
|
||||
Result.Kind := tkKeyword;
|
||||
Result.Text := ReadIdentifier;
|
||||
if Result.Text.IsEmpty then
|
||||
Result.Kind := tkError;
|
||||
end;
|
||||
else
|
||||
if c.IsDigit or ((c = '-') and (FCurrentPos < Length(FSource)) and FSource[FCurrentPos + 1].IsDigit) then
|
||||
begin
|
||||
@@ -326,6 +351,41 @@ begin
|
||||
Consume(tkRightBracket);
|
||||
end;
|
||||
|
||||
function TParser.ParseRecordLiteral: IAstNode;
|
||||
var
|
||||
fields: TList<TRecordFieldLiteral>;
|
||||
fieldName: string;
|
||||
fieldValue: IAstNode;
|
||||
begin
|
||||
Consume(tkLeftBrace);
|
||||
fields := TList<TRecordFieldLiteral>.Create;
|
||||
try
|
||||
while FCurrentToken.Kind <> tkRightBrace do
|
||||
begin
|
||||
if FCurrentToken.Kind = tkEOF then
|
||||
raise Exception.Create('Syntax Error: Unexpected end of file in record literal.');
|
||||
|
||||
// Key must be a keyword
|
||||
if FCurrentToken.Kind <> tkKeyword then
|
||||
raise Exception.Create('Syntax Error: Expected keyword (e.g., :key) as field name in record literal.');
|
||||
fieldName := FCurrentToken.Text;
|
||||
NextToken;
|
||||
|
||||
// Value can be any expression
|
||||
if FCurrentToken.Kind = tkRightBrace then
|
||||
raise Exception.Create('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
|
||||
fieldValue := ParseExpression.Node;
|
||||
|
||||
fields.Add(TRecordFieldLiteral.Create(fieldName, fieldValue));
|
||||
end;
|
||||
|
||||
Result := TAst.RecordLiteral(fields.ToArray);
|
||||
finally
|
||||
fields.Free;
|
||||
end;
|
||||
Consume(tkRightBrace);
|
||||
end;
|
||||
|
||||
function TParser.ParseList: IAstNode;
|
||||
|
||||
var
|
||||
@@ -504,6 +564,11 @@ begin
|
||||
Result.Node := TAst.Constant(FCurrentToken.Text);
|
||||
NextToken;
|
||||
end;
|
||||
tkKeyword:
|
||||
begin
|
||||
Result.Node := TAst.Keyword(FCurrentToken.Text);
|
||||
NextToken;
|
||||
end;
|
||||
tkIdentifier:
|
||||
begin
|
||||
Result.Node := TAst.Identifier(FCurrentToken.Text);
|
||||
@@ -511,6 +576,7 @@ begin
|
||||
end;
|
||||
tkLeftParen: Result.Node := ParseList;
|
||||
tkLeftBracket: Result.Params := ParseParameterList;
|
||||
tkLeftBrace: Result.Node := ParseRecordLiteral;
|
||||
tkEOF: {nop};
|
||||
else
|
||||
raise Exception.CreateFmt('Syntax Error: Unexpected token %s', [FCurrentToken.Kind.ToString]);
|
||||
@@ -590,6 +656,12 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||
begin
|
||||
Append(':' + Node.Value.Name);
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||
begin
|
||||
Append('(' + Node.Operator.ToString);
|
||||
@@ -829,6 +901,31 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||
var
|
||||
field: TRecordFieldLiteral;
|
||||
begin
|
||||
if Length(Node.Fields) = 0 then
|
||||
begin
|
||||
Append('{}');
|
||||
exit(TDataValue.Void);
|
||||
end;
|
||||
|
||||
Append('{');
|
||||
Indent;
|
||||
for field in Node.Fields do
|
||||
begin
|
||||
NewLine;
|
||||
Append(':' + field.Name);
|
||||
Append(' ');
|
||||
field.Value.Accept(Self);
|
||||
end;
|
||||
Unindent;
|
||||
NewLine;
|
||||
Append('}');
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
begin
|
||||
Append(Format('(new-series "%s")', [Node.Definition]));
|
||||
@@ -896,10 +993,14 @@ begin
|
||||
tkRightParen: Result := ')';
|
||||
tkLeftBracket: Result := '[';
|
||||
tkRightBracket: Result := ']';
|
||||
tkLeftBrace: Result := '{';
|
||||
tkRightBrace: Result := '}';
|
||||
tkQuote: Result := '''';
|
||||
tkBacktick: Result := '`';
|
||||
tkTilde: Result := '~';
|
||||
tkAt: Result := '@';
|
||||
tkIdentifier: Result := '<identifier>';
|
||||
tkKeyword: Result := '<keyword>';
|
||||
tkNumber: Result := '<number>';
|
||||
tkString: Result := '<string>';
|
||||
tkEOF: Result := '<EOF>';
|
||||
|
||||
Reference in New Issue
Block a user