Parse call expressions

This commit is contained in:
2025-06-07 23:50:33 +02:00
parent c9c9b217a2
commit a137a74468
5 changed files with 646 additions and 416 deletions

View File

@ -1,6 +1,6 @@
IMPLEMENTATION MODULE Transpiler;
FROM FIO IMPORT StdErr, WriteNBytes, WriteLine, WriteChar, WriteString;
FROM FIO IMPORT WriteNBytes, WriteLine, WriteChar, WriteString;
FROM SYSTEM IMPORT ADR, ADDRESS, TSIZE;
FROM NumberIO IMPORT IntToStr;
@ -9,14 +9,14 @@ FROM MemUtils IMPORT MemCopy, MemZero;
FROM Common IMPORT Identifier, PIdentifier, ShortString;
FROM Lexer IMPORT Lexer, LexerToken, lexer_current, lexer_lex, LexerKind;
FROM Parser IMPORT AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator,
AstModule, PAstModule, AstExpression, PAstExpression, PAstLiteral,
PAstConstantDeclaration, PPAstConstantDeclaration,
FROM Parser IMPORT AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator, AstBinaryOperator,
AstModule, PAstModule, AstExpression, PPAstExpression, PAstExpression, PAstLiteral,
PAstConstantDeclaration, PPAstConstantDeclaration, PAstStatement, AstStatementKind,
AstTypeDeclaration, PAstTypeDeclaration, PPAstTypeDeclaration,
PAstVariableDeclaration, PPAstVariableDeclaration, PAstImportStatement, PPAstImportStatement,
PAstTypeExpression, PPAstTypeExpression, AstFieldDeclaration, PAstFieldDeclaration,
parse_type_expression, parse_variable_part, parse_type_part, parse_constant_part, parse_import_part,
parse_designator;
parse_designator, parse_expression;
(* Calls lexer_lex() but skips the comments. *)
PROCEDURE transpiler_lex(lexer: PLexer): LexerToken;
@ -40,8 +40,12 @@ END write_semicolon;
PROCEDURE write_current(lexer: PLexer; output: File);
VAR
written_bytes: CARDINAL;
count: CARDINAL;
BEGIN
written_bytes := WriteNBytes(output, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start)
count := lexer^.current;
DEC(count, lexer^.start);
written_bytes := WriteNBytes(output, count, lexer^.start)
END write_current;
PROCEDURE transpile_import_statement(context: PTranspilerContext; import_statement: PAstImportStatement);
VAR
@ -385,59 +389,6 @@ BEGIN
RETURN result
END transpile_procedure_heading;
PROCEDURE transpile_unchanged(context: PTranspilerContext; trailing_token: LexerKind);
VAR
token: LexerToken;
written_bytes: CARDINAL;
BEGIN
token := lexer_current(context^.lexer);
WHILE (token.kind <> trailing_token) AND (token.kind <> lexerKindEnd) DO
written_bytes := 0;
IF token.kind = lexerKindNull THEN
WriteString(context^.output, 'NIL ');
written_bytes := 1
END;
IF (token.kind = lexerKindBoolean) AND token.booleanKind THEN
WriteString(context^.output, 'TRUE ');
written_bytes := 1
END;
IF (token.kind = lexerKindBoolean) AND (~token.booleanKind) THEN
WriteString(context^.output, 'FALSE ');
written_bytes := 1
END;
IF token.kind = lexerKindOr THEN
WriteString(context^.output, 'OR ');
written_bytes := 1
END;
IF token.kind = lexerKindAnd THEN
WriteString(context^.output, 'AND ');
written_bytes := 1
END;
IF token.kind = lexerKindTilde THEN
WriteString(context^.output, 'NOT ');
written_bytes := 1
END;
IF written_bytes = 0 THEN
write_current(context^.lexer, context^.output);
WriteChar(context^.output, ' ')
END;
token := transpiler_lex(context^.lexer)
END
END transpile_unchanged;
PROCEDURE parse_expression(lexer: PLexer): PAstExpression;
VAR
next_token: LexerToken;
result: PAstExpression;
written_bytes: CARDINAL;
BEGIN
result := parse_designator(lexer);
written_bytes := WriteNBytes(StdErr, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start);
WriteLine(StdErr);
RETURN result
END parse_expression;
PROCEDURE transpile_unary_operator(context: PTranspilerContext; operator: AstUnaryOperator);
BEGIN
IF operator = astUnaryOperatorMinus THEN
@ -447,11 +398,49 @@ BEGIN
WriteChar(context^.output, '~')
END
END transpile_unary_operator;
PROCEDURE transpile_binary_operator(context: PTranspilerContext; operator: AstBinaryOperator);
BEGIN
IF operator = astBinaryOperatorSum THEN
WriteChar(context^.output, '+')
END;
IF operator = astBinaryOperatorSubtraction THEN
WriteChar(context^.output, '-')
END;
IF operator = astBinaryOperatorMultiplication THEN
WriteChar(context^.output, '*')
END;
IF operator = astBinaryOperatorEquals THEN
WriteChar(context^.output, '=')
END;
IF operator = astBinaryOperatorNotEquals THEN
WriteChar(context^.output, '#')
END;
IF operator = astBinaryOperatorLess THEN
WriteChar(context^.output, '<')
END;
IF operator = astBinaryOperatorGreater THEN
WriteChar(context^.output, '>')
END;
IF operator = astBinaryOperatorLessEqual THEN
WriteString(context^.output, '<=')
END;
IF operator = astBinaryOperatorGreaterEqual THEN
WriteString(context^.output, '>=')
END;
IF operator = astBinaryOperatorDisjunction THEN
WriteString(context^.output, 'OR')
END;
IF operator = astBinaryOperatorConjunction THEN
WriteString(context^.output, 'AND')
END
END transpile_binary_operator;
PROCEDURE transpile_expression(context: PTranspilerContext; expression: PAstExpression);
VAR
literal: PAstLiteral;
buffer: ARRAY[1..20] OF CHAR;
written_bytes: CARDINAL;
argument_index: CARDINAL;
current_argument: PPAstExpression;
BEGIN
IF expression^.kind = astExpressionKindLiteral THEN
literal := expression^.literal;
@ -462,7 +451,16 @@ BEGIN
END;
IF literal^.kind = astLiteralKindString THEN
WriteString(context^.output, literal^.string)
END
END;
IF literal^.kind = astLiteralKindNull THEN
WriteString(context^.output, 'NIL')
END;
IF (literal^.kind = astLiteralKindBoolean) AND literal^.boolean THEN
WriteString(context^.output, 'TRUE')
END;
IF (literal^.kind = astLiteralKindBoolean) AND (literal^.boolean = FALSE) THEN
WriteString(context^.output, 'FALSE')
END
END;
IF expression^.kind = astExpressionKindIdentifier THEN
written_bytes := WriteNBytes(context^.output, ORD(expression^.identifier[1]), ADR(expression^.identifier[2]))
@ -485,57 +483,100 @@ BEGIN
IF expression^.kind = astExpressionKindUnary THEN
transpile_unary_operator(context, expression^.unary_operator);
transpile_expression(context, expression^.unary_operand)
END;
IF expression^.kind = astExpressionKindBinary THEN
WriteChar(context^.output, '(');
transpile_expression(context, expression^.lhs);
WriteChar(context^.output, ' ');
transpile_binary_operator(context, expression^.binary_operator);
WriteChar(context^.output, ' ');
transpile_expression(context, expression^.rhs);
WriteChar(context^.output, ')')
END;
IF expression^.kind = astExpressionKindCall THEN
transpile_expression(context, expression^.callable);
WriteChar(context^.output, '(');
current_argument := expression^.arguments;
IF expression^.argument_count > 0 THEN
transpile_expression(context, current_argument^);
argument_index := 1;
INC(current_argument, TSIZE(PAstExpression));
WHILE argument_index < expression^.argument_count DO
WriteString(context^.output, ', ');
transpile_expression(context, current_argument^);
INC(current_argument, TSIZE(PAstExpression));
INC(argument_index)
END
END;
WriteChar(context^.output, ')')
END
END transpile_expression;
PROCEDURE transpile_if_statement(context: PTranspilerContext);
PROCEDURE transpile_if_statement(context: PTranspilerContext): PAstStatement;
VAR
token: LexerToken;
expression: PAstExpression;
lexer: Lexer;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindIf;
WriteString(context^.output, ' IF ');
lexer := context^.lexer^;
token := transpiler_lex(ADR(lexer));
expression := parse_expression(ADR(lexer));
token := transpiler_lex(context^.lexer);
result^.if_condition := parse_expression(context^.lexer);
IF expression <> NIL THEN
context^.lexer^ := lexer;
transpile_expression(context, expression);
WriteChar(context^.output, ' ')
END;
IF expression = NIL THEN
token := transpiler_lex(context^.lexer)
END;
transpile_unchanged(context, lexerKindThen);
transpile_expression(context, result^.if_condition);
token := lexer_current(context^.lexer);
WriteString(context^.output, 'THEN');
WriteString(context^.output, ' THEN');
WriteLine(context^.output);
transpile_statements(context);
WriteString(context^.output, ' END');
token := transpiler_lex(context^.lexer)
token := transpiler_lex(context^.lexer);
RETURN result
END transpile_if_statement;
PROCEDURE transpile_while_statement(context: PTranspilerContext);
PROCEDURE transpile_while_statement(context: PTranspilerContext): PAstStatement;
VAR
token: LexerToken;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindWhile;
WriteString(context^.output, ' WHILE ');
token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindDo);
WriteString(context^.output, 'DO');
token := transpiler_lex(context^.lexer);
result^.while_condition := parse_expression(context^.lexer);
transpile_expression(context, result^.while_condition);
token := lexer_current(context^.lexer);
WriteString(context^.output, ' DO');
WriteLine(context^.output);
transpile_statements(context);
WriteString(context^.output, ' END');
token := transpiler_lex(context^.lexer)
token := transpiler_lex(context^.lexer);
RETURN result
END transpile_while_statement;
PROCEDURE transpile_assignment_statement(context: PTranspilerContext);
PROCEDURE transpile_assignment_statement(context: PTranspilerContext; assignee: PAstExpression): PAstStatement;
VAR
token: LexerToken;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindAssignment;
result^.assignee := assignee;
WriteString(context^.output, ' := ');
token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindSemicolon);
result^.assignment := parse_expression(context^.lexer);
transpile_expression(context, result^.assignment);
RETURN result
END transpile_assignment_statement;
PROCEDURE transpile_call_statement(context: PTranspilerContext);
VAR
@ -549,78 +590,48 @@ BEGIN
token := transpiler_lex(context^.lexer)
END
END transpile_call_statement;
PROCEDURE transpile_designator_expression(context: PTranspilerContext);
VAR
token: LexerToken;
BEGIN
WriteString(context^.output, ' ');
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer);
WHILE token.kind = lexerKindLeftSquare DO
WriteChar(context^.output, '[');
token := transpiler_lex(context^.lexer);
WHILE token.kind <> lexerKindRightSquare DO
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer)
END;
WriteChar(context^.output, ']');
token := transpiler_lex(context^.lexer)
END;
IF token.kind = lexerKindHat THEN
WriteChar(context^.output, '^');
token := transpiler_lex(context^.lexer)
END;
IF token.kind = lexerKindDot THEN
WriteChar(context^.output, '.');
token := transpiler_lex(context^.lexer);
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer)
END;
IF token.kind = lexerKindHat THEN
WriteChar(context^.output, '^');
token := transpiler_lex(context^.lexer)
END;
WHILE token.kind = lexerKindLeftSquare DO
WriteChar(context^.output, '[');
token := transpiler_lex(context^.lexer);
WHILE token.kind <> lexerKindRightSquare DO
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer)
END;
WriteChar(context^.output, ']');
token := transpiler_lex(context^.lexer)
END
END transpile_designator_expression;
PROCEDURE transpile_return_statement(context: PTranspilerContext);
PROCEDURE transpile_return_statement(context: PTranspilerContext): PAstStatement;
VAR
token: LexerToken;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindReturn;
WriteString(context^.output, ' RETURN ');
token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindSemicolon)
result^.returned := parse_expression(context^.lexer);
transpile_expression(context, result^.returned);
RETURN result
END transpile_return_statement;
PROCEDURE transpile_statement(context: PTranspilerContext);
VAR
token: LexerToken;
written_bytes: CARDINAL;
statement: PAstStatement;
designator: PAstExpression;
BEGIN
token := transpiler_lex(context^.lexer);
IF token.kind = lexerKindIf THEN
transpile_if_statement(context)
statement := transpile_if_statement(context)
END;
IF token.kind = lexerKindWhile THEN
transpile_while_statement(context)
statement := transpile_while_statement(context)
END;
IF token.kind = lexerKindReturn THEN
transpile_return_statement(context)
statement := transpile_return_statement(context)
END;
IF token.kind = lexerKindIdentifier THEN
transpile_designator_expression(context);
designator := parse_designator(context^.lexer);
transpile_expression(context, designator);
token := lexer_current(context^.lexer);
IF token.kind = lexerKindAssignment THEN
transpile_assignment_statement(context)
statement := transpile_assignment_statement(context, designator);
token := lexer_current(context^.lexer)
END;
IF token.kind = lexerKindLeftParen THEN
transpile_call_statement(context)