ranged for loop
This commit is contained in:
parent
96a7c656e9
commit
d5910989d1
@ -512,9 +512,11 @@ pub const Block = struct {
|
||||
};
|
||||
|
||||
pub const Loop = struct {
|
||||
pre: Value.Index,
|
||||
condition: Value.Index,
|
||||
body: Value.Index,
|
||||
breaks: bool,
|
||||
post: Value.Index,
|
||||
reaches_end: bool,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
@ -528,6 +530,12 @@ const Unresolved = struct {
|
||||
pub const Assignment = struct {
|
||||
destination: Value.Index,
|
||||
source: Value.Index,
|
||||
operation: Operation,
|
||||
|
||||
const Operation = enum {
|
||||
none,
|
||||
add,
|
||||
};
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
@ -651,10 +659,14 @@ pub const FieldAccess = struct {
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Slice = struct {
|
||||
sliceable: Value.Index,
|
||||
pub const Range = struct {
|
||||
start: Value.Index,
|
||||
end: Value.Index,
|
||||
};
|
||||
|
||||
pub const Slice = struct {
|
||||
sliceable: Value.Index,
|
||||
range: Range,
|
||||
type: Type.Index,
|
||||
|
||||
pub const Access = struct {
|
||||
|
@ -130,7 +130,25 @@ pub const TranslationUnit = struct {
|
||||
.value_index = declaration.init_value,
|
||||
.type_index = declaration.type,
|
||||
});
|
||||
try list.append(allocator, ';');
|
||||
}
|
||||
|
||||
fn writeAssignment(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, assignment_index: Compilation.Assignment.Index, function_return_type: Compilation.Type.Index, indentation: usize) !void {
|
||||
const assignment = module.assignments.get(assignment_index);
|
||||
const left_type = module.values.get(assignment.source).getType(module);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = assignment.destination,
|
||||
.type_index = left_type,
|
||||
});
|
||||
try list.append(allocator, ' ');
|
||||
switch (assignment.operation) {
|
||||
.none => {},
|
||||
.add => try list.append(allocator, '+'),
|
||||
}
|
||||
try list.appendSlice(allocator, "= ");
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = assignment.source,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
}
|
||||
|
||||
fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, function_return_type: Compilation.Type.Index, old_indentation: usize) !void {
|
||||
@ -146,19 +164,10 @@ pub const TranslationUnit = struct {
|
||||
switch (statement.*) {
|
||||
.declaration => |declaration_index| {
|
||||
try unit.writeDeclaration(module, list, allocator, declaration_index, indentation);
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.assign => |assignment_index| {
|
||||
const assignment = module.assignments.get(assignment_index);
|
||||
const left_type = module.values.get(assignment.source).getType(module);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = assignment.destination,
|
||||
.type_index = left_type,
|
||||
});
|
||||
try list.appendSlice(allocator, " = ");
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = assignment.source,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
try unit.writeAssignment(module, list, allocator, assignment_index, function_return_type, indentation);
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.@"return" => |return_index| {
|
||||
@ -245,6 +254,38 @@ pub const TranslationUnit = struct {
|
||||
try unit.writeAssembly(module, list, allocator, assembly_block_index, indentation);
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.loop => |loop_index| {
|
||||
const loop = module.loops.get(loop_index);
|
||||
try list.appendSlice(allocator, "for (");
|
||||
if (!loop.pre.invalid) {
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = loop.pre,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
}
|
||||
try list.appendSlice(allocator, "; ");
|
||||
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = loop.condition,
|
||||
.type_index = Compilation.Type.boolean,
|
||||
});
|
||||
|
||||
try list.appendSlice(allocator, "; ");
|
||||
|
||||
if (!loop.post.invalid) {
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = loop.post,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
}
|
||||
|
||||
try list.appendSlice(allocator, ") ");
|
||||
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = loop.body,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
@ -326,6 +367,7 @@ pub const TranslationUnit = struct {
|
||||
=> {},
|
||||
.@"struct" => {
|
||||
try unit.writeDeclaration(module, &unit.global_variable_declarations, allocator, declaration_index, 0);
|
||||
try unit.global_variable_declarations.append(allocator, ';');
|
||||
try unit.global_variable_declarations.appendNTimes(allocator, '\n', 2);
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
@ -798,6 +840,12 @@ pub const TranslationUnit = struct {
|
||||
_ = type_index;
|
||||
const value = module.values.get(value_index);
|
||||
switch (value.*) {
|
||||
.declaration => |declaration_index| {
|
||||
try unit.writeDeclaration(module, list, allocator, declaration_index, indentation);
|
||||
},
|
||||
.assign => |assignment_index| {
|
||||
try unit.writeAssignment(module, list, allocator, assignment_index, function_return_type, indentation);
|
||||
},
|
||||
.integer => |integer| {
|
||||
try list.writer(allocator).print("{}", .{integer.value});
|
||||
},
|
||||
@ -996,7 +1044,7 @@ pub const TranslationUnit = struct {
|
||||
});
|
||||
try list.appendSlice(allocator, ") + (");
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{
|
||||
.value_index = slice.start,
|
||||
.value_index = slice.range.start,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
try list.appendSlice(allocator, "),\n");
|
||||
@ -1009,16 +1057,16 @@ pub const TranslationUnit = struct {
|
||||
|
||||
switch (sliceable_type.*) {
|
||||
.pointer => {
|
||||
switch (slice.end.invalid) {
|
||||
switch (slice.range.end.invalid) {
|
||||
false => {
|
||||
try list.append(allocator, '(');
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{
|
||||
.value_index = slice.end,
|
||||
.value_index = slice.range.end,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
try list.appendSlice(allocator, ") - (");
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{
|
||||
.value_index = slice.start,
|
||||
.value_index = slice.range.start,
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
try list.appendSlice(allocator, ")\n");
|
||||
|
@ -50,6 +50,7 @@ pub const Token = packed struct(u64) {
|
||||
fixed_keyword_align = 0x1b,
|
||||
fixed_keyword_export = 0x1c,
|
||||
fixed_keyword_cc = 0x1d,
|
||||
fixed_keyword_for = 0x1e,
|
||||
keyword_unsigned_integer = 0x1f,
|
||||
keyword_signed_integer = 0x20,
|
||||
bang = '!', // 0x21
|
||||
@ -114,6 +115,7 @@ pub const FixedKeyword = enum {
|
||||
@"align",
|
||||
@"export",
|
||||
cc,
|
||||
@"for",
|
||||
};
|
||||
|
||||
pub const Result = struct {
|
||||
|
@ -18,6 +18,7 @@ const Field = Compilation.Field;
|
||||
const Function = Compilation.Function;
|
||||
const Intrinsic = Compilation.Intrinsic;
|
||||
const Loop = Compilation.Loop;
|
||||
const Range = Compilation.Range;
|
||||
const Scope = Compilation.Scope;
|
||||
const ScopeType = Compilation.ScopeType;
|
||||
const Slice = Compilation.Slice;
|
||||
@ -106,7 +107,9 @@ const Analyzer = struct {
|
||||
current_file: File.Index,
|
||||
current_declaration: Declaration.Index = Declaration.Index.invalid,
|
||||
payloads: ArrayList(Payload) = .{},
|
||||
current_block: Block.Index = Block.Index.invalid,
|
||||
maybe_count: usize = 0,
|
||||
for_count: usize = 0,
|
||||
|
||||
fn getScopeSourceFile(analyzer: *Analyzer, scope_index: Scope.Index) []const u8 {
|
||||
const scope = analyzer.module.scopes.get(scope_index);
|
||||
@ -188,14 +191,20 @@ const Analyzer = struct {
|
||||
});
|
||||
const scope_index = new_scope.index;
|
||||
|
||||
var statements = ArrayList(Value.Index){};
|
||||
const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{
|
||||
.statements = ArrayList(Value.Index){},
|
||||
.reaches_end = true,
|
||||
});
|
||||
const block_index = block_allocation.index;
|
||||
const previous_block = analyzer.current_block;
|
||||
analyzer.current_block = block_index;
|
||||
|
||||
for (analyzer.payloads.items) |payload| {
|
||||
const declaration_index = try analyzer.declarationCommon(scope_index, .local, payload.mutability, payload.name, payload.type, payload.value, null);
|
||||
const statement_value_allocation = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.declaration = declaration_index,
|
||||
});
|
||||
try statements.append(analyzer.allocator, statement_value_allocation.index);
|
||||
try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, statement_value_allocation.index);
|
||||
}
|
||||
|
||||
analyzer.payloads.clearRetainingCapacity();
|
||||
@ -215,25 +224,9 @@ const Analyzer = struct {
|
||||
|
||||
const statement_node = analyzer.getScopeNode(scope_index, statement_node_index);
|
||||
logln(.sema, .node, "Trying to resolve statement of id {s}", .{@tagName(statement_node.id)});
|
||||
|
||||
const statement_value_index = switch (statement_node.id) {
|
||||
.assign => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processAssignment(scope_index, statement_node_index))).index,
|
||||
.simple_while => blk: {
|
||||
const loop_allocation = try analyzer.module.loops.append(analyzer.allocator, .{
|
||||
.condition = Value.Index.invalid,
|
||||
.body = Value.Index.invalid,
|
||||
.breaks = false,
|
||||
});
|
||||
loop_allocation.ptr.condition = (try analyzer.unresolvedAllocate(scope_index, ExpectType.boolean, statement_node.left)).index;
|
||||
loop_allocation.ptr.body = (try analyzer.unresolvedAllocate(scope_index, ExpectType.none, statement_node.right)).index;
|
||||
|
||||
// TODO: bool true
|
||||
reaches_end = loop_allocation.ptr.breaks or unreachable;
|
||||
|
||||
const value_allocation = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.loop = loop_allocation.index,
|
||||
});
|
||||
break :blk value_allocation.index;
|
||||
},
|
||||
.assign, .add_assign => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processAssignment(scope_index, statement_node_index))).index,
|
||||
.@"unreachable" => blk: {
|
||||
reaches_end = false;
|
||||
break :blk unreachable_index;
|
||||
@ -300,7 +293,7 @@ const Analyzer = struct {
|
||||
const if_else_value = try analyzer.processIfElse(scope_index, expect_type, if_else_node_index, payload_node_index);
|
||||
|
||||
if (if_else_value.maybe_payload_declaration_index) |maybe_payload_declaration| {
|
||||
try statements.append(analyzer.allocator, maybe_payload_declaration);
|
||||
try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, maybe_payload_declaration);
|
||||
}
|
||||
|
||||
const branch = analyzer.module.branches.get(if_else_value.branch);
|
||||
@ -328,7 +321,7 @@ const Analyzer = struct {
|
||||
const if_expression = try analyzer.processIf(scope_index, expect_type, if_statement_node_index, payload_node_index);
|
||||
|
||||
if (if_expression.maybe_payload_declaration_value) |maybe_payload_declaration| {
|
||||
try statements.append(analyzer.allocator, maybe_payload_declaration);
|
||||
try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, maybe_payload_declaration);
|
||||
}
|
||||
|
||||
const branch = try analyzer.module.branches.append(analyzer.allocator, .{
|
||||
@ -352,18 +345,24 @@ const Analyzer = struct {
|
||||
const value = try analyzer.module.values.append(analyzer.allocator, assembly_value);
|
||||
break :blk value.index;
|
||||
},
|
||||
.for_loop => blk: {
|
||||
const loop_index = try analyzer.forLoop(scope_index, expect_type, statement_node_index);
|
||||
const value = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.loop = loop_index,
|
||||
});
|
||||
break :blk value.index;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
try statements.append(analyzer.allocator, statement_value_index);
|
||||
try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, statement_value_index);
|
||||
}
|
||||
|
||||
const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{
|
||||
.statements = statements,
|
||||
.reaches_end = reaches_end,
|
||||
});
|
||||
analyzer.module.blocks.get(block_index).reaches_end = reaches_end;
|
||||
|
||||
return block_allocation.index;
|
||||
analyzer.current_block = previous_block;
|
||||
|
||||
return block_index;
|
||||
}
|
||||
|
||||
fn processAssemblyStatements(analyzer: *Analyzer, comptime architecture: type, scope_index: Scope.Index, assembly_statement_nodes: []const Node.Index) ![]Compilation.Assembly.Instruction.Index {
|
||||
@ -796,6 +795,126 @@ const Analyzer = struct {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn range(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Range {
|
||||
const range_node = analyzer.getScopeNode(scope_index, node_index);
|
||||
assert(range_node.id == .range);
|
||||
|
||||
const expect_type = ExpectType{
|
||||
.type_index = Type.usize,
|
||||
};
|
||||
|
||||
const range_start = try analyzer.unresolvedAllocate(scope_index, expect_type, range_node.left);
|
||||
const range_end = try analyzer.unresolvedAllocate(scope_index, expect_type, range_node.right);
|
||||
|
||||
return Range{
|
||||
.start = range_start.index,
|
||||
.end = range_end.index,
|
||||
};
|
||||
}
|
||||
|
||||
fn forLoop(analyzer: *Analyzer, parent_scope_index: Scope.Index, expect_type: ExpectType, for_node_index: Node.Index) !Loop.Index {
|
||||
const for_loop_node = analyzer.getScopeNode(parent_scope_index, for_node_index);
|
||||
assert(for_loop_node.id == .for_loop);
|
||||
|
||||
const scope_allocation = try analyzer.allocateScope(.{
|
||||
.token = for_loop_node.token,
|
||||
.file = analyzer.module.scopes.get(parent_scope_index).file,
|
||||
.parent = parent_scope_index,
|
||||
});
|
||||
const scope_index = scope_allocation.index;
|
||||
const for_condition_node = analyzer.getScopeNode(scope_index, for_loop_node.left);
|
||||
assert(for_condition_node.id == .for_condition);
|
||||
|
||||
const for_loop_element_node = analyzer.getScopeNode(scope_index, for_condition_node.left);
|
||||
var pre = Value.Index.invalid;
|
||||
const for_condition = switch (for_loop_element_node.id) {
|
||||
.range => blk: {
|
||||
const for_range = try analyzer.range(scope_index, for_condition_node.left);
|
||||
|
||||
const for_loop_payload_node = analyzer.getScopeNode(scope_index, for_condition_node.right);
|
||||
const payload_name = switch (for_loop_payload_node.id) {
|
||||
.node_list => b: {
|
||||
const nodes = analyzer.getScopeNodeList(scope_index, for_loop_payload_node);
|
||||
assert(nodes.items.len == 1);
|
||||
const payload_node = analyzer.getScopeNode(scope_index, nodes.items[0]);
|
||||
const result = analyzer.tokenIdentifier(scope_index, payload_node.token);
|
||||
break :b result;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const declaration_index = try analyzer.declarationCommon(scope_index, .local, .@"var", payload_name, Type.usize, for_range.start, null);
|
||||
const declaration_value = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.declaration = declaration_index,
|
||||
});
|
||||
pre = declaration_value.index;
|
||||
|
||||
const binary_condition = try analyzer.module.binary_operations.append(analyzer.allocator, .{
|
||||
.id = .compare_less_than,
|
||||
.type = Type.boolean,
|
||||
.left = try analyzer.doIdentifierString(scope_index, ExpectType{
|
||||
.type_index = Type.usize,
|
||||
}, payload_name),
|
||||
.right = for_range.end,
|
||||
});
|
||||
|
||||
const condition = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.binary_operation = binary_condition.index,
|
||||
});
|
||||
break :blk condition.index;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
const for_loop_body = try analyzer.unresolvedAllocate(scope_index, expect_type, for_loop_node.right);
|
||||
var post = Value.Index.invalid;
|
||||
switch (for_loop_element_node.id) {
|
||||
.range => {
|
||||
const for_condition_value = analyzer.module.values.get(for_condition);
|
||||
switch (for_condition_value.*) {
|
||||
.binary_operation => |binary_operation_index| {
|
||||
const binary_operation = analyzer.module.binary_operations.get(binary_operation_index);
|
||||
const left = binary_operation.left;
|
||||
const right = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.integer = .{
|
||||
.value = 1,
|
||||
.type = Type.usize,
|
||||
.signedness = .unsigned,
|
||||
},
|
||||
});
|
||||
|
||||
const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
|
||||
.operation = .add,
|
||||
.destination = left,
|
||||
.source = right.index,
|
||||
});
|
||||
|
||||
const assignment_value = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.assign = assignment.index,
|
||||
});
|
||||
post = assignment_value.index;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
const reaches_end = switch (for_loop_body.ptr.*) {
|
||||
.block => |block_index| analyzer.module.blocks.get(block_index).reaches_end,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
const loop = try analyzer.module.loops.append(analyzer.allocator, .{
|
||||
.pre = pre,
|
||||
.condition = for_condition,
|
||||
.body = for_loop_body.index,
|
||||
.reaches_end = reaches_end,
|
||||
.post = post,
|
||||
});
|
||||
|
||||
return loop.index;
|
||||
}
|
||||
|
||||
const If = struct {
|
||||
maybe_payload_declaration_value: ?Value.Index,
|
||||
expression: Value.Index,
|
||||
@ -935,11 +1054,11 @@ const Analyzer = struct {
|
||||
|
||||
fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
|
||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||
assert(node.id == .assign);
|
||||
assert(!node.left.invalid);
|
||||
const left_node = analyzer.getScopeNode(scope_index, node.left);
|
||||
switch (left_node.id) {
|
||||
.discard => {
|
||||
assert(node.id == .assign);
|
||||
var result = Value{
|
||||
.unresolved = .{
|
||||
.node_index = node.right,
|
||||
@ -964,6 +1083,11 @@ const Analyzer = struct {
|
||||
const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
|
||||
.destination = left.index,
|
||||
.source = right.index,
|
||||
.operation = switch (node.id) {
|
||||
.assign => .none,
|
||||
.add_assign => .add,
|
||||
else => unreachable,
|
||||
},
|
||||
});
|
||||
|
||||
return Value{
|
||||
@ -1734,15 +1858,10 @@ const Analyzer = struct {
|
||||
.pointer => |pointer| pointer.element_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const slice_range_node = analyzer.getScopeNode(scope_index, node.right);
|
||||
assert(slice_range_node.id == .slice_range);
|
||||
const slice_range_start = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, slice_range_node.left);
|
||||
const slice_range_end = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, slice_range_node.right);
|
||||
|
||||
const slice = try analyzer.module.slices.append(analyzer.allocator, .{
|
||||
.sliceable = expression_to_slice.index,
|
||||
.start = slice_range_start.index,
|
||||
.end = slice_range_end.index,
|
||||
.range = try analyzer.range(scope_index, node.right),
|
||||
.type = try analyzer.getSliceType(.{
|
||||
.element_type = element_type,
|
||||
.@"const" = true,
|
||||
|
@ -165,7 +165,7 @@ pub const Node = struct {
|
||||
if_payload,
|
||||
discard,
|
||||
slice,
|
||||
slice_range,
|
||||
range,
|
||||
negation,
|
||||
anonymous_container_literal,
|
||||
const_single_pointer_type,
|
||||
@ -175,6 +175,9 @@ pub const Node = struct {
|
||||
assembly_register,
|
||||
assembly_statement,
|
||||
assembly_block,
|
||||
for_condition,
|
||||
for_loop,
|
||||
add_assign,
|
||||
};
|
||||
};
|
||||
|
||||
@ -429,7 +432,7 @@ const Analyzer = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn block(analyzer: *Analyzer, options: Options) !Node.Index {
|
||||
fn block(analyzer: *Analyzer, options: Options) anyerror!Node.Index {
|
||||
const left_brace = try analyzer.expectToken(.left_brace);
|
||||
var list = ArrayList(Node.Index){};
|
||||
|
||||
@ -448,6 +451,7 @@ const Analyzer = struct {
|
||||
.fixed_keyword_while => try analyzer.whileExpression(options),
|
||||
.fixed_keyword_switch => try analyzer.switchExpression(),
|
||||
.fixed_keyword_if => try analyzer.ifExpression(),
|
||||
.fixed_keyword_for => try analyzer.forExpression(),
|
||||
.fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(),
|
||||
.hash => blk: {
|
||||
const intrinsic = try analyzer.compilerIntrinsic();
|
||||
@ -620,23 +624,117 @@ const Analyzer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn assignExpression(analyzer: *Analyzer) !Node.Index {
|
||||
const expr = try analyzer.expression();
|
||||
const expression_id: Node.Id = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.semicolon, .comma => return expr,
|
||||
.equal => .assign,
|
||||
fn forExpression(analyzer: *Analyzer) !Node.Index {
|
||||
const token = try analyzer.expectToken(.fixed_keyword_for);
|
||||
_ = try analyzer.expectToken(.left_parenthesis);
|
||||
const expression_token = analyzer.token_i;
|
||||
const first = try analyzer.expression();
|
||||
const ForExpression = struct {
|
||||
node_index: Node.Index,
|
||||
expected_payload_count: usize,
|
||||
};
|
||||
const for_expression = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.period => switch (analyzer.tokens[analyzer.token_i + 1].id) {
|
||||
.period => blk: {
|
||||
analyzer.token_i += 2;
|
||||
const second = try analyzer.expression();
|
||||
|
||||
break :blk ForExpression{
|
||||
.node_index = try analyzer.addNode(.{
|
||||
.id = .range,
|
||||
.token = expression_token,
|
||||
.left = first,
|
||||
.right = second,
|
||||
}),
|
||||
.expected_payload_count = 1,
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
_ = try analyzer.expectToken(.right_parenthesis);
|
||||
|
||||
_ = try analyzer.expectToken(.vertical_bar);
|
||||
|
||||
var payload_nodes = ArrayList(Node.Index){};
|
||||
while (analyzer.tokens[analyzer.token_i].id != .vertical_bar) {
|
||||
const payload_identifier = try analyzer.expectToken(.identifier);
|
||||
|
||||
switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.vertical_bar => {},
|
||||
.comma => analyzer.token_i += 1,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
try payload_nodes.append(analyzer.allocator, try analyzer.addNode(.{
|
||||
.id = .identifier,
|
||||
.token = payload_identifier,
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
}));
|
||||
}
|
||||
|
||||
_ = try analyzer.expectToken(.vertical_bar);
|
||||
|
||||
if (payload_nodes.items.len != for_expression.expected_payload_count) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const for_condition_node = try analyzer.addNode(.{
|
||||
.id = .for_condition,
|
||||
.token = token,
|
||||
.left = for_expression.node_index,
|
||||
.right = try analyzer.nodeList(payload_nodes),
|
||||
});
|
||||
|
||||
const for_content_node = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.left_brace => try analyzer.block(.{
|
||||
.is_comptime = false,
|
||||
}),
|
||||
else => blk: {
|
||||
const for_content_expression = try analyzer.expression();
|
||||
_ = try analyzer.expectToken(.semicolon);
|
||||
break :blk for_content_expression;
|
||||
},
|
||||
};
|
||||
|
||||
const for_node = try analyzer.addNode(.{
|
||||
.id = .for_loop,
|
||||
.token = token,
|
||||
.left = for_condition_node,
|
||||
.right = for_content_node,
|
||||
});
|
||||
|
||||
return for_node;
|
||||
}
|
||||
|
||||
fn assignExpression(analyzer: *Analyzer) !Node.Index {
|
||||
const left = try analyzer.expression();
|
||||
const expression_token = analyzer.token_i;
|
||||
const expression_id: Node.Id = switch (analyzer.tokens[expression_token].id) {
|
||||
.semicolon, .comma => return left,
|
||||
.equal => .assign,
|
||||
.plus => switch (analyzer.tokens[analyzer.token_i + 1].id) {
|
||||
.equal => blk: {
|
||||
analyzer.token_i += 1;
|
||||
break :blk .add_assign;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
analyzer.token_i += 1;
|
||||
|
||||
const right = try analyzer.expression();
|
||||
|
||||
const node = Node{
|
||||
.id = expression_id,
|
||||
.token = blk: {
|
||||
const token_i = analyzer.token_i;
|
||||
analyzer.token_i += 1;
|
||||
break :blk token_i;
|
||||
},
|
||||
.left = expr,
|
||||
.right = try analyzer.expression(),
|
||||
.token = expression_token,
|
||||
.left = left,
|
||||
.right = right,
|
||||
};
|
||||
|
||||
logln(.parser, .assign, "assign:\nleft: {}.\nright: {}", .{ node.left, node.right });
|
||||
@ -837,6 +935,7 @@ const Analyzer = struct {
|
||||
.comma,
|
||||
.fixed_keyword_const,
|
||||
.fixed_keyword_var,
|
||||
.fixed_keyword_return,
|
||||
.identifier,
|
||||
=> break,
|
||||
else => blk: {
|
||||
@ -854,7 +953,7 @@ const Analyzer = struct {
|
||||
},
|
||||
.plus => switch (next_token_id) {
|
||||
.plus => unreachable,
|
||||
.equal => unreachable,
|
||||
.equal => break,
|
||||
else => .add,
|
||||
},
|
||||
.minus => switch (next_token_id) {
|
||||
@ -1470,7 +1569,7 @@ const Analyzer = struct {
|
||||
.token = token,
|
||||
.left = left,
|
||||
.right = try analyzer.addNode(.{
|
||||
.id = .slice_range,
|
||||
.id = .range,
|
||||
.token = token,
|
||||
.left = index_expression,
|
||||
.right = range_end_expression,
|
||||
|
@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void {
|
||||
all = b.option(bool, "all", "All") orelse false;
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimization = b.standardOptimizeOption(.{});
|
||||
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse false;
|
||||
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true;
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "nativity",
|
||||
.root_source_file = .{ .path = "bootstrap/main.zig" },
|
||||
|
10
test/foreach/main.nat
Normal file
10
test/foreach/main.nat
Normal file
@ -0,0 +1,10 @@
|
||||
const main = fn () s32 {
|
||||
var counter: s32 = 0;
|
||||
const loop = 10;
|
||||
|
||||
for (0..loop) |_| {
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
return loop - counter;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user