Implement cast expressions

This commit is contained in:
2026-05-13 22:52:07 +02:00
parent eaa7fc2ca2
commit 1802aa21d8
3 changed files with 229 additions and 32 deletions
+4 -11
View File
@@ -46,18 +46,11 @@ task :convert do
current_stage << <<~FUN
proc f();
var
x: ElnaLocation;
y: ElnaPosition;
x: ^ElnaLocation;
begin
x.line := 5;
x.column := 3;
y.end_location := x;
(* y.end_location.line := 5;
y.end_location.column := 3;
x := y.end_location; *)
printf("# %i %i %i %i\\n\\0", x.line, x.column, y.end_location.line, y.end_location.column)
x := malloc(#size(ElnaLocation));
x^.line := 5;
x^.column := cast(3: Word)
end;
begin
+217 -21
View File
@@ -8,6 +8,7 @@ program;
(* Stage 21 compiler. *)
(* - Allow assigning variables refering to aggregates. *)
(* - Cast expressions. *)
type
ElnaListNode = record
@@ -102,11 +103,15 @@ type
array_type_expression,
null,
trait_expression,
array_access_expression
array_access_expression,
_cast
);
ElnaTreeNode = record
kind: ElnaTreeKind
end;
ElnaTreeTypeExpression = record
kind: ElnaTreeKind
end;
ElnaTreeExpression = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType
@@ -131,17 +136,23 @@ type
type_decoration: ^ElnaType;
value: Word
end;
ElnaTreeStringLiteral = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType;
value: Word;
length: Word
end;
ElnaTreeVariableExpression = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType;
name: Word;
length: Word
end;
ElnaTreeStringLiteral = record
ElnaTreeCastExpression = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType;
value: Word;
length: Word
expression: ^ElnaTreeExpression;
type_expression: ^ElnaTreeTypeExpression
end;
ElnaTreeDereferenceExpression = record
kind: ElnaTreeKind;
@@ -158,7 +169,7 @@ type
ElnaTreeUnaryExpression = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType;
operand: Word;
operand: ^ElnaTreeExpression;
operator: Word
end;
@@ -225,7 +236,7 @@ type
ElnaTreeField = record
name: Word;
length: Word;
type_expression: ^ElnaTreeNode;
type_expression: ^ElnaTreeTypeExpression;
next: Word
end;
ElnaTreeRecordTypeExpression = record
@@ -240,11 +251,11 @@ type
end;
ElnaTreePointerTypeExpression = record
kind: ElnaTreeKind;
base: ^ElnaTreeNode
base: ^ElnaTreeTypeExpression
end;
ElnaTreeArrayTypeExpression = record
kind: ElnaTreeKind;
base: ^ElnaTreeNode;
base: ^ElnaTreeTypeExpression;
length: Word
end;
ElnaTreeTraitExpression = record
@@ -276,7 +287,7 @@ type
body: ^ElnaTreeStatement;
temporaries: Word;
parameters: Word;
return_type: ^ElnaTreeNode
return_type: ^ElnaTreeTypeExpression
end;
ElnaTreeModuleDeclaration = record
kind: ElnaTreeKind;
@@ -290,14 +301,14 @@ type
next: Word;
name: Word;
length: Word;
_type: Word
type_expression: ^ElnaTreeTypeExpression
end;
ElnaTreeVariableDeclaration = record
kind: ElnaTreeKind;
next: Word;
name: Word;
length: Word;
_type: Word
type_expression: Word
end;
ElnaTreeExpressionList = record
expression: ^ElnaTreeBinaryExpression;
@@ -2366,6 +2377,28 @@ begin
return result
end;
proc elna_parser_cast_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeCastExpression;
var
result: ^ElnaTreeCastExpression;
token: ^ElnaLexerToken;
begin
result := malloc(#size(ElnaTreeCastExpression));
result^.kind := ElnaTreeKind._cast;
result^.type_decoration := nil;
(* Skip the cast keyword and opening paren. *)
elna_lexer_read(cursor);
elna_lexer_read(cursor);
result^.expression := elna_parser_binary_expression(cursor);
(* Skip the colon. *)
elna_lexer_read(cursor);
result^.type_expression := elna_parser_type_expression(cursor);
(* Skip the closing paren. *)
elna_lexer_read(cursor);
return result
end;
proc elna_parser_simple_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeExpression;
var
current_character: Word;
@@ -2385,6 +2418,8 @@ begin
parser_node := elna_parser_boolean_literal(cursor)
elsif token^.kind = ElnaLexerKind.null then
parser_node := elna_parser_nil_literal(cursor)
elsif token^.kind = ElnaLexerKind._cast then
parser_node := elna_parser_cast_expression(cursor)
elsif token^.kind = ElnaLexerKind.trait then
parser_node := elna_parser_trait_expression(cursor)
elsif token^.kind = ElnaLexerKind.identifier then
@@ -2449,6 +2484,12 @@ begin
operand^.length := 0
end;
proc elna_tac_cast_expression(instructions: ^ElnaList, parser_node: ^ElnaTreeCastExpression,
symbol_table: ^ElnaSymbolTable, operand: ^ElnaTacOperand);
begin
elna_tac_binary_expression(instructions, parser_node^.expression, symbol_table, operand)
end;
proc elna_tac_simple_expression(instructions: ^ElnaList, parser_node: ^ElnaTreeNode,
symbol_table: ^ElnaSymbolTable, operand: ^ElnaTacOperand);
begin
@@ -2462,6 +2503,8 @@ begin
elna_tac_boolean_literal(parser_node, operand)
elsif parser_node^.kind = ElnaTreeKind.null then
elna_tac_nil_literal(parser_node, operand)
elsif parser_node^.kind = ElnaTreeKind._cast then
elna_tac_cast_expression(instructions, parser_node, symbol_table, operand)
elsif parser_node^.kind = ElnaTreeKind.trait_expression then
elna_tac_trait_expression(parser_node, operand)
else
@@ -3761,7 +3804,7 @@ begin
return result
end;
proc type_info_create(type_representation: Word) -> ^ElnaSymbolTypeInfo;
proc type_info_create(type_representation: ^ElnaType) -> ^ElnaSymbolTypeInfo;
var
result: ^ElnaSymbolTypeInfo;
begin
@@ -3815,7 +3858,7 @@ var
info: Word;
variable_type: Word;
begin
variable_type := elna_name_type_expression(parser_node^._type);
variable_type := elna_name_type_expression(parser_node^.type_expression);
info := temporary_info_create(0, variable_type);
elna_symbol_table_enter(symbol_table, parser_node^.name, parser_node^.length, info)
@@ -4274,7 +4317,7 @@ begin
result^.length := token^.length;
elna_lexer_read(cursor);
result^._type := elna_parser_type_expression(cursor);
result^.type_expression := elna_parser_type_expression(cursor);
elna_lexer_read(cursor);
@@ -4286,7 +4329,7 @@ var
symbol_type: ^ElnaType;
type_info: ^ElnaSymbolTypeInfo;
begin
symbol_type := elna_name_type_expression(parser_node^._type);
symbol_type := elna_name_type_expression(parser_node^.type_expression);
type_info := type_info_create(symbol_type);
elna_symbol_table_enter(symbol_table_global, parser_node^.name, parser_node^.length, type_info)
@@ -4350,7 +4393,7 @@ begin
result^.next := nil;
result^.name := token^.start;
result^.length := token^.length;
result^._type := variable_type;
result^.type_expression := variable_type;
return result
end;
@@ -4539,6 +4582,152 @@ begin
return result
end;
proc elna_name_dereference_expression(parser_node: ^ElnaTreeDereferenceExpression);
begin
elna_name_designator(parser_node^.pointer)
end;
proc elna_name_field_access_expression(parser_node: ^ElnaTreeFieldAccessExpression);
begin
elna_name_designator(parser_node^.aggregate)
end;
proc elna_name_array_access_expression(parser_node: ^ElnaTreeArrayAccessExpression);
begin
elna_name_designator(parser_node^.array);
elna_name_binary_expression(parser_node^.index)
end;
proc elna_name_cast_expression(parser_node: ^ElnaTreeCastExpression);
begin
elna_name_binary_expression(parser_node^.expression);
parser_node^.type_decoration := elna_name_type_expression(parser_node^.type_expression)
end;
proc elna_name_simple_expression(parser_node: ^ElnaTreeNode);
begin
(* Not interested in literals and variable expressions. *)
if parser_node^.kind = ElnaTreeKind._cast then
elna_name_cast_expression(parser_node)
end
end;
proc elna_name_call(parser_node: ^ElnaTreeCall);
var
argument_tree: ^ElnaTreeExpressionList;
begin
argument_tree := parser_node^.arguments;
.elna_name_call_argument;
if argument_tree <> nil then
elna_name_binary_expression(argument_tree^.expression);
argument_tree := argument_tree^.next;
goto elna_name_call_argument
end
end;
proc elna_name_designator(parser_node: ^ElnaTreeNode);
begin
if parser_node^.kind = ElnaTreeKind.dereference_expression then
elna_name_dereference_expression(parser_node)
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
elna_name_field_access_expression(parser_node)
elsif parser_node^.kind = ElnaTreeKind.array_access_expression then
elna_name_array_access_expression(parser_node)
elsif parser_node^.kind = ElnaTreeKind.call then
elna_name_call(parser_node)
else
elna_name_simple_expression(parser_node)
end
end;
proc elna_name_unary_expression(parser_node: ^ElnaTreeUnaryExpression);
begin
if parser_node^.kind = ElnaTreeKind.unary_expression then
elna_name_designator(parser_node^.operand)
else
elna_name_designator(parser_node)
end
end;
proc elna_name_binary_expression(parser_node: ^ElnaTreeBinaryExpression);
begin
if parser_node^.kind = ElnaTreeKind.binary_expression then
elna_name_unary_expression(parser_node^.lhs);
elna_name_unary_expression(parser_node^.rhs)
else
elna_name_unary_expression(parser_node)
end
end;
proc elna_name_conditional_statements(parser_node: ^ElnaTreeConditionalStatements);
begin
.elna_name_conditional_statements_loop;
elna_name_binary_expression(parser_node^.condition);
elna_name_statements(parser_node^.statements);
parser_node := parser_node^.next;
if parser_node <> nil then
goto elna_name_conditional_statements_loop
end
end;
proc elna_name_if_statement(parser_node: ^ElnaTreeIfStatement);
var
block: ^ElnaTreeConditionalStatements;
begin
block := parser_node^.conditionals;
.elna_name_if_statement_conditionals;
elna_name_conditional_statements(block);
block := block^.next;
if block <> nil then
goto elna_name_if_statement_conditionals
end;
block := parser_node^._else;
if block <> nil then
elna_name_statements(block)
end
end;
proc elna_name_return_statement(parser_node: ^ElnaTreeReturnStatement);
begin
elna_name_binary_expression(parser_node^.returned)
end;
proc elna_name_assign_statement(parser_node: ^ElnaTreeAssignStatement);
begin
elna_name_designator(parser_node^.assignee);
elna_name_binary_expression(parser_node^.assignment)
end;
proc elna_name_statement(parser_node: ^ElnaTreeStatement);
begin
(* Skipping goto and label declarations. *)
if parser_node^.kind = ElnaTreeKind.if_statement then
elna_name_if_statement(parser_node)
elsif parser_node^.kind = ElnaTreeKind.return_statement then
elna_name_return_statement(parser_node)
elsif parser_node^.kind = ElnaTreeKind.call then
elna_name_call(parser_node)
elsif parser_node^.kind = ElnaTreeKind.assign_statement then
elna_name_assign_statement(parser_node)
end
end;
proc elna_name_statements(parser_node: ^ElnaTreeStatement);
begin
.elna_name_statements_loop;
if parser_node <> nil then
elna_name_statement(parser_node);
parser_node := parser_node^.next;
goto elna_name_statements_loop
end
end;
proc elna_name_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration);
var
new_symbol_table: ^ElnaSymbolTable;
@@ -4549,6 +4738,7 @@ begin
elna_name_procedure_temporaries(parser_node^.parameters, new_symbol_table);
elna_name_procedure_temporaries(parser_node^.temporaries, new_symbol_table);
elna_name_statements(parser_node^.body);
elna_symbol_table_enter(symbol_table_global, parser_node^.name, parser_node^.length, symbol_info)
end;
@@ -4690,6 +4880,11 @@ begin
end
end;
proc elna_type_cast_expression(parser_node: ^ElnaTreeCastExpression, symbol_table: ^ElnaSymbolTable);
begin
elna_type_binary_expression(parser_node^.expression, symbol_table)
end;
proc elna_type_simple_expression(parser_node: ^ElnaTreeNode, symbol_table: ^ElnaSymbolTable);
begin
if parser_node^.kind = ElnaTreeKind.integer_literal then
@@ -4702,6 +4897,8 @@ begin
elna_type_boolean_literal(parser_node)
elsif parser_node^.kind = ElnaTreeKind.null then
elna_type_nil_literal(parser_node)
elsif parser_node^.kind = ElnaTreeKind._cast then
elna_type_cast_expression(parser_node)
elsif parser_node^.kind = ElnaTreeKind.variable_expression then
elna_type_variable_expression(parser_node, symbol_table)
end
@@ -4801,14 +4998,11 @@ begin
end;
proc elna_type_unary_expression(parser_node: ^ElnaTreeUnaryExpression, symbol_table: ^ElnaSymbolTable);
var
unary_operand: ^ElnaTreeExpression;
begin
if parser_node^.kind = ElnaTreeKind.unary_expression then
unary_operand := parser_node^.operand;
elna_type_designator(unary_operand, symbol_table);
elna_type_designator(parser_node^.operand, symbol_table);
parser_node^.type_decoration := unary_operand^.type_decoration
parser_node^.type_decoration := parser_node^.operand^.type_decoration
else
elna_type_designator(parser_node, symbol_table)
end
@@ -5496,6 +5690,8 @@ begin
result^.kind := ElnaLexerKind.boolean
elsif string_compare(position_start, result^.length, "false", 5) then
result^.kind := ElnaLexerKind.boolean
elsif string_compare(position_start, result^.length, "cast", 4) then
result^.kind := ElnaLexerKind._cast
end;
return result
end;
+8
View File
@@ -74,3 +74,11 @@ end
file "build/valid/#{STAGES.last}/cl" => 'build/build.ninja' do |t|
sh 'ninja', '-f', t.prerequisites.first
end
namespace :ninja do
desc 'Forces the regeneration of build/build.ninja'
task :build do
rm_f 'build/build.ninja'
Rake::Task['build/build.ninja'].invoke
end
end