authorchloe caruso <git@paperclover.net> 2024-07-21 05:50:56-07:00
committerchloe caruso <git@paperclover.net> 2024-07-21 05:50:56-07:00
log93f206223985b78c60faad1d965986089c08d424
treef249221ca243702565e5c5c1537568cb16dd4505
parent168537d7484a99f4cb88cc3622c9125e1eadb910

feat(transform): include a warning for leading zero in numbers


7 files changed, 57 insertions(+), 25 deletions(-)

CHANGELOG.md+1
......@@ -3,6 +3,7 @@
33- feat: implement string identifiers
44- feat: implement basic struct types
55- feat: include a `README.html` alongside compiler with documentation and code samples.
6- feat(transform): include a warning for leading zero in numbers
67- fix(sema): miscompilation using left side of all binary expression for both sides
78- fix(sema): handle recursive function calls
89- fix(sema): quit block analysis when hitting `noreturn`
src/core/Ast.zig+1-1
......@@ -763,7 +763,7 @@ pub fn extraData(tree: Ast, index: usize, comptime T: type) T {
763763 OptionalExtraIndex,
764764 => 1,
765765 SubList => 2,
766 else => comptime unreachable,
766 else => @compileError(unreachable),
767767 };
768768 }
769769 return result;
src/core/Parse.zig+1-1
......@@ -867,7 +867,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
867867 .kw_comptime => .@"comptime",
868868 .kw_pure => .pure,
869869 .kw_assert => .assert,
870 else => comptime unreachable,
870 else => @compileError(unreachable),
871871 },
872872 .main_token = main_token,
873873 .data = .{ .un = .{
src/core/Report.zig+44-15
......@@ -424,6 +424,25 @@ pub const Warn = union(enum) {
424424 try ctx.msgAlone("if this was intentional, discard it with \"_ = {};\"", .{formatIdCode(id)});
425425 }
426426 },
427 zero_prefixed_literal: struct {
428 token: TokenIndex,
429
430 fn build(data: @This(), ctx: *MsgContext) !void {
431 try ctx.msg(.{
432 .token_substring = .{
433 .token = data.token,
434 .start = 0,
435 .len = brk: {
436 const slice = ctx.ast.tokenSlice(data.token);
437 var i: u32 = 0;
438 while (slice[i] == '0') i += 1;
439 if (slice[i] == '.') i -= 1;
440 break :brk i;
441 },
442 },
443 }, "avoid redundant zeros in numbers", .{});
444 }
445 },
427446 not_mutated_var: struct {
428447 node: NodeIndex,
429448
......@@ -814,19 +833,21 @@ const Component = struct {
814833};
815834
816835pub const Highlight = union(enum) {
817 // No source view
836 /// No source view
818837 alone,
819 // Highlight one token
838 /// Highlight one token
820839 token: TokenIndex,
821 // Highlight one token without referring to the Ast
840 /// Highlight one token without referring to the Ast
822841 token_stored: Tokenizer.Token,
823 // Highlight two tokens
842 /// Highlight two tokens
824843 two_tokens: TokenIndex,
825 // Highlight a Node
844 /// Highlight a substring of a token
845 token_substring: struct { token: TokenIndex, start: ByteOffset, len: u32 },
846 /// Highlight a Node
826847 node: NodeIndex,
827 // Highlight a codepoint
848 /// Highlight a codepoint
828849 codepoint: ByteOffset,
829 // Highlight from the start of a codepoint to '\n'
850 /// Highlight from the start of a codepoint to '\n'
830851 codepoint_eol: ByteOffset,
831852
832853 pub fn loc(highlight: Highlight, ast: *const Ast) ?SliceLoc {
......@@ -834,22 +855,30 @@ pub const Highlight = union(enum) {
834855 .alone => null,
835856 inline .node,
836857 .token,
858 .token_substring,
837859 .two_tokens,
838860 => |payload, tag| loc: {
839861 const token_index: TokenIndex = switch (tag) {
840862 .node => ast.nodeToken(payload),
841863 .token, .two_tokens => payload,
842 else => comptime unreachable,
864 .token_substring => payload.token,
865 else => @compileError(unreachable),
843866 };
844867
845 const location = ast.tokenLocation(0, token_index);
846868 const token = ast.tokens.get(token_index);
847869
848 break :loc .{
849 .loc = location,
850 .slice = token.slice(ast.utf8_source),
851 .byte = token.offset,
852 };
870 var location = ast.tokenLocation(0, token_index);
871 var slice = token.slice(ast.utf8_source);
872 var byte = token.offset;
873
874 if (tag == .token_substring) {
875 location.column = location.column.add(payload.start);
876 slice.ptr += payload.start;
877 slice.len = payload.len;
878 byte += payload.start;
879 }
880
881 break :loc .{ .loc = location, .slice = slice, .byte = byte };
853882 },
854883 .token_stored => |token| loc: {
855884 const location = Tokenizer.tokenLocation(ast.utf8_source, 0, token.offset);
......@@ -869,7 +898,7 @@ pub const Highlight = union(enum) {
869898 n
870899 else
871900 (ast.utf8_source.len - b),
872 else => comptime unreachable,
901 else => @compileError(unreachable),
873902 };
874903 break :loc .{
875904 .byte = b,
src/core/Sema.zig+3-3
......@@ -1328,7 +1328,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
13281328 .sub => l - r,
13291329 .mul => l * r,
13301330 .div => l / r,
1331 else => comptime unreachable,
1331 else => @compileError(unreachable),
13321332 };
13331333
13341334 return try s.makeValue(if (left_ty == .numeric_literal)
......@@ -1346,7 +1346,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
13461346 .sub => std.math.sub(i32, l, r),
13471347 .mul => std.math.mul(i32, l, r),
13481348 .div => return try s.makeValue(.{ .float = @as(f64, @floatFromInt(l)) / @as(f64, @floatFromInt(r)) }),
1349 else => comptime unreachable,
1349 else => @compileError(unreachable),
13501350 } catch @panic("TODO: out of range");
13511351
13521352 return try s.makeValue(.{ .int32 = result });
......@@ -1362,7 +1362,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
13621362 const result = switch (tag) {
13631363 .lt => l < r,
13641364 .gt => l > r,
1365 else => comptime unreachable,
1365 else => @compileError(unreachable),
13661366 };
13671367 return @as(
13681368 InternPool.Value,
src/core/Tokenizer.zig+1-4
......@@ -612,9 +612,7 @@ fn tokenizeIdentifier(t: *Tokenizer, start_byte: u32) !Token {
612612/// - May use 0x, 0b, 0o prefixes for hex, binary, octal numbers.
613613/// The token is tagged as `number_int` or `number_float` depending
614614/// on if it contained a `.` This is to help later re-parses.
615//
616// TODO: is it a zig compiler bug that `?` is required here?
617fn tokenizeNumber(t: *Tokenizer) !?Token {
615fn tokenizeNumber(t: *Tokenizer) !Token {
618616 const trace = T.trace(@src());
619617 defer trace.end();
620618
......@@ -646,7 +644,6 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {
646644 t.pos += 2;
647645 try t.consumeIntegerRadix(.octal);
648646 },
649 '0' => @panic("TODO: no double zero"),
650647 else => break :alt_base,
651648 }
652649
src/core/Transform.zig+6-1
......@@ -797,8 +797,13 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
797797 const value = switch (tag) {
798798 .number_int => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),
799799 .number_float => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),
800 else => comptime unreachable,
800 else => @compileError(unreachable),
801801 };
802
803 if (value != 0 and text[0] == '0' and (text.len == 1 or text[1] != '.')) {
804 try t.report.warn(.zero_prefixed_literal, .{ .token = t.ast.nodeToken(node) });
805 }
806
802807 return try t.addInstRef(.{
803808 .tag = .number,
804809 .data = EncodedData.encode(.number, .{