authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-21 05:50:56-07:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-21 05:50:56-07:00
log30c8ffc2374e7a7222bca85dac7507bf17abbe51
treef249221ca243702565e5c5c1537568cb16dd4505
parentaea9afc99a3c2ab279c066e0e42216304a49200a
signature Commit is signed but in an unrecognized format.

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


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

CHANGELOG.md+1
...@@ -3,6 +3,7 @@...@@ -3,6 +3,7 @@
3- feat: implement string identifiers3- feat: implement string identifiers
4- feat: implement basic struct types4- feat: implement basic struct types
5- feat: include a `README.html` alongside compiler with documentation and code samples.5- feat: include a `README.html` alongside compiler with documentation and code samples.
6- feat(transform): include a warning for leading zero in numbers
6- fix(sema): miscompilation using left side of all binary expression for both sides7- fix(sema): miscompilation using left side of all binary expression for both sides
7- fix(sema): handle recursive function calls8- fix(sema): handle recursive function calls
8- fix(sema): quit block analysis when hitting `noreturn`9- 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 {...@@ -763,7 +763,7 @@ pub fn extraData(tree: Ast, index: usize, comptime T: type) T {
763 OptionalExtraIndex,763 OptionalExtraIndex,
764 => 1,764 => 1,
765 SubList => 2,765 SubList => 2,
766 else => comptime unreachable,766 else => @compileError(unreachable),
767 };767 };
768 }768 }
769 return result;769 return result;
src/core/Parse.zig+1-1
...@@ -867,7 +867,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {...@@ -867,7 +867,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
867 .kw_comptime => .@"comptime",867 .kw_comptime => .@"comptime",
868 .kw_pure => .pure,868 .kw_pure => .pure,
869 .kw_assert => .assert,869 .kw_assert => .assert,
870 else => comptime unreachable,870 else => @compileError(unreachable),
871 },871 },
872 .main_token = main_token,872 .main_token = main_token,
873 .data = .{ .un = .{873 .data = .{ .un = .{
src/core/Report.zig+44-15
...@@ -424,6 +424,25 @@ pub const Warn = union(enum) {...@@ -424,6 +424,25 @@ pub const Warn = union(enum) {
424 try ctx.msgAlone("if this was intentional, discard it with \"_ = {};\"", .{formatIdCode(id)});424 try ctx.msgAlone("if this was intentional, discard it with \"_ = {};\"", .{formatIdCode(id)});
425 }425 }
426 },426 },
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 },
427 not_mutated_var: struct {446 not_mutated_var: struct {
428 node: NodeIndex,447 node: NodeIndex,
429448
...@@ -814,19 +833,21 @@ const Component = struct {...@@ -814,19 +833,21 @@ const Component = struct {
814};833};
815834
816pub const Highlight = union(enum) {835pub const Highlight = union(enum) {
817 // No source view836 /// No source view
818 alone,837 alone,
819 // Highlight one token838 /// Highlight one token
820 token: TokenIndex,839 token: TokenIndex,
821 // Highlight one token without referring to the Ast840 /// Highlight one token without referring to the Ast
822 token_stored: Tokenizer.Token,841 token_stored: Tokenizer.Token,
823 // Highlight two tokens842 /// Highlight two tokens
824 two_tokens: TokenIndex,843 two_tokens: TokenIndex,
825 // Highlight a Node844 /// Highlight a substring of a token
845 token_substring: struct { token: TokenIndex, start: ByteOffset, len: u32 },
846 /// Highlight a Node
826 node: NodeIndex,847 node: NodeIndex,
827 // Highlight a codepoint848 /// Highlight a codepoint
828 codepoint: ByteOffset,849 codepoint: ByteOffset,
829 // Highlight from the start of a codepoint to '\n'850 /// Highlight from the start of a codepoint to '\n'
830 codepoint_eol: ByteOffset,851 codepoint_eol: ByteOffset,
831852
832 pub fn loc(highlight: Highlight, ast: *const Ast) ?SliceLoc {853 pub fn loc(highlight: Highlight, ast: *const Ast) ?SliceLoc {
...@@ -834,22 +855,30 @@ pub const Highlight = union(enum) {...@@ -834,22 +855,30 @@ pub const Highlight = union(enum) {
834 .alone => null,855 .alone => null,
835 inline .node,856 inline .node,
836 .token,857 .token,
858 .token_substring,
837 .two_tokens,859 .two_tokens,
838 => |payload, tag| loc: {860 => |payload, tag| loc: {
839 const token_index: TokenIndex = switch (tag) {861 const token_index: TokenIndex = switch (tag) {
840 .node => ast.nodeToken(payload),862 .node => ast.nodeToken(payload),
841 .token, .two_tokens => payload,863 .token, .two_tokens => payload,
842 else => comptime unreachable,864 .token_substring => payload.token,
865 else => @compileError(unreachable),
843 };866 };
844867
845 const location = ast.tokenLocation(0, token_index);
846 const token = ast.tokens.get(token_index);868 const token = ast.tokens.get(token_index);
847869
848 break :loc .{870 var location = ast.tokenLocation(0, token_index);
849 .loc = location,871 var slice = token.slice(ast.utf8_source);
850 .slice = token.slice(ast.utf8_source),872 var byte = token.offset;
851 .byte = token.offset,873
852 };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 };
853 },882 },
854 .token_stored => |token| loc: {883 .token_stored => |token| loc: {
855 const location = Tokenizer.tokenLocation(ast.utf8_source, 0, token.offset);884 const location = Tokenizer.tokenLocation(ast.utf8_source, 0, token.offset);
...@@ -869,7 +898,7 @@ pub const Highlight = union(enum) {...@@ -869,7 +898,7 @@ pub const Highlight = union(enum) {
869 n898 n
870 else899 else
871 (ast.utf8_source.len - b),900 (ast.utf8_source.len - b),
872 else => comptime unreachable,901 else => @compileError(unreachable),
873 };902 };
874 break :loc .{903 break :loc .{
875 .byte = b,904 .byte = b,
src/core/Sema.zig+3-3
...@@ -1328,7 +1328,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {...@@ -1328,7 +1328,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
1328 .sub => l - r,1328 .sub => l - r,
1329 .mul => l * r,1329 .mul => l * r,
1330 .div => l / r,1330 .div => l / r,
1331 else => comptime unreachable,1331 else => @compileError(unreachable),
1332 };1332 };
13331333
1334 return try s.makeValue(if (left_ty == .numeric_literal)1334 return try s.makeValue(if (left_ty == .numeric_literal)
...@@ -1346,7 +1346,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {...@@ -1346,7 +1346,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
1346 .sub => std.math.sub(i32, l, r),1346 .sub => std.math.sub(i32, l, r),
1347 .mul => std.math.mul(i32, l, r),1347 .mul => std.math.mul(i32, l, r),
1348 .div => return try s.makeValue(.{ .float = @as(f64, @floatFromInt(l)) / @as(f64, @floatFromInt(r)) }),1348 .div => return try s.makeValue(.{ .float = @as(f64, @floatFromInt(l)) / @as(f64, @floatFromInt(r)) }),
1349 else => comptime unreachable,1349 else => @compileError(unreachable),
1350 } catch @panic("TODO: out of range");1350 } catch @panic("TODO: out of range");
13511351
1352 return try s.makeValue(.{ .int32 = result });1352 return try s.makeValue(.{ .int32 = result });
...@@ -1362,7 +1362,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {...@@ -1362,7 +1362,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Value {
1362 const result = switch (tag) {1362 const result = switch (tag) {
1363 .lt => l < r,1363 .lt => l < r,
1364 .gt => l > r,1364 .gt => l > r,
1365 else => comptime unreachable,1365 else => @compileError(unreachable),
1366 };1366 };
1367 return @as(1367 return @as(
1368 InternPool.Value,1368 InternPool.Value,
src/core/Tokenizer.zig+1-4
...@@ -612,9 +612,7 @@ fn tokenizeIdentifier(t: *Tokenizer, start_byte: u32) !Token {...@@ -612,9 +612,7 @@ fn tokenizeIdentifier(t: *Tokenizer, start_byte: u32) !Token {
612/// - May use 0x, 0b, 0o prefixes for hex, binary, octal numbers.612/// - May use 0x, 0b, 0o prefixes for hex, binary, octal numbers.
613/// The token is tagged as `number_int` or `number_float` depending613/// The token is tagged as `number_int` or `number_float` depending
614/// on if it contained a `.` This is to help later re-parses.614/// on if it contained a `.` This is to help later re-parses.
615//615fn tokenizeNumber(t: *Tokenizer) !Token {
616// TODO: is it a zig compiler bug that `?` is required here?
617fn tokenizeNumber(t: *Tokenizer) !?Token {
618 const trace = T.trace(@src());616 const trace = T.trace(@src());
619 defer trace.end();617 defer trace.end();
620618
...@@ -646,7 +644,6 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {...@@ -646,7 +644,6 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {
646 t.pos += 2;644 t.pos += 2;
647 try t.consumeIntegerRadix(.octal);645 try t.consumeIntegerRadix(.octal);
648 },646 },
649 '0' => @panic("TODO: no double zero"),
650 else => break :alt_base,647 else => break :alt_base,
651 }648 }
652649
src/core/Transform.zig+6-1
...@@ -797,8 +797,13 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -797,8 +797,13 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
797 const value = switch (tag) {797 const value = switch (tag) {
798 .number_int => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),798 .number_int => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),
799 .number_float => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),799 .number_float => std.fmt.parseFloat(f64, text) catch @panic("TODO: write my own float parser"),
800 else => comptime unreachable,800 else => @compileError(unreachable),
801 };801 };
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
802 return try t.addInstRef(.{807 return try t.addInstRef(.{
803 .tag = .number,808 .tag = .number,
804 .data = EncodedData.encode(.number, .{809 .data = EncodedData.encode(.number, .{