diff --git a/Rakefile b/Rakefile index 8b18106..499a70b 100644 --- a/Rakefile +++ b/Rakefile @@ -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 diff --git a/boot/stage21/cl.elna b/boot/stage21/cl.elna index 35777ba..72d7e01 100644 --- a/boot/stage21/cl.elna +++ b/boot/stage21/cl.elna @@ -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; diff --git a/rakelib/ninja.rake b/rakelib/ninja.rake index de213ef..3d9a994 100644 --- a/rakelib/ninja.rake +++ b/rakelib/ninja.rake @@ -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