Scripting refinement
This commit is contained in:
+72
-22
@@ -41,6 +41,10 @@ type
|
||||
tkError
|
||||
);
|
||||
|
||||
TTokenKindHelper = record helper for TTokenKind
|
||||
function ToString: String;
|
||||
end;
|
||||
|
||||
TToken = record
|
||||
Kind: TTokenKind;
|
||||
Text: string;
|
||||
@@ -63,6 +67,7 @@ type
|
||||
TExpr = record
|
||||
Token: TToken;
|
||||
Node: IAstNode;
|
||||
Params: TArray<IIdentifierNode>;
|
||||
end;
|
||||
|
||||
TParser = class
|
||||
@@ -246,7 +251,7 @@ end;
|
||||
procedure TParser.Consume(AExpectedKind: TTokenKind);
|
||||
begin
|
||||
if FCurrentToken.Kind <> AExpectedKind then
|
||||
raise Exception.CreateFmt('Syntax Error: Expected token %d, but found %d', [Ord(AExpectedKind), Ord(FCurrentToken.Kind)]);
|
||||
raise Exception.CreateFmt('Syntax Error: Expected token %s, but found %s', [AExpectedKind.ToString, FCurrentToken.Kind.ToString]);
|
||||
NextToken;
|
||||
end;
|
||||
|
||||
@@ -259,6 +264,8 @@ begin
|
||||
try
|
||||
while FCurrentToken.Kind <> tkRightBracket do
|
||||
begin
|
||||
if FCurrentToken.Kind = tkEOF then
|
||||
raise Exception.Create('Syntax Error: Unexpected end of file.');
|
||||
if FCurrentToken.Kind <> tkIdentifier then
|
||||
raise Exception.Create('Syntax Error: Expected identifier in parameter list.');
|
||||
params.Add(TAst.Identifier(FCurrentToken.Text));
|
||||
@@ -284,7 +291,6 @@ function TParser.ParseList: IAstNode;
|
||||
var
|
||||
elements: TList<TExpr>;
|
||||
head: TExpr;
|
||||
headIdent: IIdentifierNode;
|
||||
tailTokens: TArray<TToken>;
|
||||
tailNodes: TArray<IAstNode>;
|
||||
begin
|
||||
@@ -295,7 +301,11 @@ begin
|
||||
elements := TList<TExpr>.Create;
|
||||
try
|
||||
while FCurrentToken.Kind <> tkRightParen do
|
||||
begin
|
||||
if FCurrentToken.Kind = tkEOF then
|
||||
raise Exception.Create('Syntax Error: Unexpected end of file.');
|
||||
elements.Add(ParseExpression);
|
||||
end;
|
||||
|
||||
head := elements[0];
|
||||
|
||||
@@ -311,37 +321,59 @@ begin
|
||||
if head.Token.Kind = tkIdentifier then
|
||||
begin
|
||||
// Handle special forms
|
||||
if SameText(headIdent.Name, 'if') then
|
||||
if SameText(head.Token.Text, 'if') then
|
||||
Result := TAst.IfExpr(tailNodes[0], tailNodes[1], IfThen(Length(tailNodes) > 2, tailNodes[2], nil))
|
||||
else if SameText(headIdent.Name, 'def') then
|
||||
else if SameText(head.Token.Text, 'def') then
|
||||
begin
|
||||
var identNode: IIdentifierNode;
|
||||
if tailTokens[0].Kind <> tkIdentifier then
|
||||
raise Exception.Create('Syntax Error: Expected an identifier for def statement.');
|
||||
Result := TAst.VarDecl(identNode, IfThen(Length(tailNodes) > 1, tailNodes[1], nil));
|
||||
Result := TAst.VarDecl(IIdentifierNode(tailNodes[0]), IfThen(Length(tailNodes) > 1, tailNodes[1], nil));
|
||||
end
|
||||
else if SameText(headIdent.Name, 'assign') then
|
||||
else if SameText(head.Token.Text, 'assign') then
|
||||
begin
|
||||
var identNode: IIdentifierNode;
|
||||
if tailTokens[0].Kind <> tkIdentifier then
|
||||
raise Exception.Create('Syntax Error: Expected an identifier for assignment.');
|
||||
Result := TAst.Assign(identNode, tailNodes[1]);
|
||||
Result := TAst.Assign(IIdentifierNode(tailNodes[0]), tailNodes[1]);
|
||||
end
|
||||
else if SameText(headIdent.Name, 'fn') then
|
||||
Result := TAst.LambdaExpr(ParseParameterList, tailNodes[0]) // Special parsing for params
|
||||
else if SameText(headIdent.Name, 'do') then
|
||||
else if SameText(head.Token.Text, 'fn') then
|
||||
Result := TAst.LambdaExpr(elements[High(tailNodes)].Params, tailNodes[1])
|
||||
else if SameText(head.Token.Text, 'do') then
|
||||
Result := TAst.Block(tailNodes)
|
||||
else if SameText(headIdent.Name, 'recur') then
|
||||
else if SameText(head.Token.Text, 'recur') then
|
||||
Result := TAst.Recur(tailNodes)
|
||||
else if SameText(headIdent.Name, 'get') then
|
||||
else if SameText(head.Token.Text, 'get') then
|
||||
Result := TAst.Indexer(tailNodes[0], tailNodes[1])
|
||||
else if (Length(headIdent.Name) > 1) and (headIdent.Name.StartsWith('.')) then
|
||||
Result := TAst.MemberAccess(tailNodes[0], TAst.Identifier(headIdent.Name.Substring(1)))
|
||||
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)))
|
||||
else
|
||||
Result := TAst.FunctionCall(head.Node, tailNodes); // Default is a function call
|
||||
end
|
||||
else
|
||||
Result := TAst.FunctionCall(head.Node, tailNodes); // Callee is a complex expression, e.g. ((fn [x] x) 1)
|
||||
begin
|
||||
if Length(tailNodes) = 1 then
|
||||
begin
|
||||
for var op := Low(TScalar.TUnaryOp) to High(TScalar.TUnaryOp) do
|
||||
begin
|
||||
if head.Token.Text = op.ToString then
|
||||
begin
|
||||
Result := TAst.UnaryExpr(op, tailNodes[0]);
|
||||
break
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if Length(tailNodes) = 2 then
|
||||
begin
|
||||
for var op := Low(TScalar.TBinaryOp) to High(TScalar.TBinaryOp) do
|
||||
begin
|
||||
if head.Token.Text = op.ToString then
|
||||
begin
|
||||
Result := TAst.BinaryExpr(tailNodes[0], op, tailNodes[1]);
|
||||
break
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if Result = nil then
|
||||
Result := TAst.FunctionCall(head.Node, tailNodes);
|
||||
|
||||
finally
|
||||
elements.Free;
|
||||
@@ -378,15 +410,17 @@ begin
|
||||
NextToken;
|
||||
end;
|
||||
tkLeftParen: Result.Node := ParseList;
|
||||
tkLeftBracket: Result.Params := ParseParameterList;
|
||||
tkEOF: {nop};
|
||||
else
|
||||
raise Exception.CreateFmt('Syntax Error: Unexpected token %d', [Ord(FCurrentToken.Kind)]);
|
||||
raise Exception.CreateFmt('Syntax Error: Unexpected token %s', [FCurrentToken.Kind.ToString]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TParser.Parse: IAstNode;
|
||||
begin
|
||||
var expr := ParseExpression;
|
||||
if expr.Token.Kind <> tkEOF then
|
||||
if FCurrentToken.Kind <> tkEOF then
|
||||
raise Exception.Create('Syntax Error: Unexpected characters after end of expression.');
|
||||
Result := expr.Node;
|
||||
end;
|
||||
@@ -696,4 +730,20 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTokenKindHelper.ToString: String;
|
||||
begin
|
||||
case Self of
|
||||
tkLeftParen: Result := '(';
|
||||
tkRightParen: Result := ')';
|
||||
tkLeftBracket: Result := '[';
|
||||
tkRightBracket: Result := ']';
|
||||
tkIdentifier: Result := '<identifier>';
|
||||
tkNumber: Result := '<number>';
|
||||
tkString: Result := '<string>';
|
||||
tkEOF: Result := '<EOF>';
|
||||
else
|
||||
Result := '<error>';
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user