aboutsummaryrefslogtreecommitdiff
path: root/deps/aro/SymbolStack.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2023-10-02 07:08:53 +0300
committerGitHub <noreply@github.com>2023-10-02 07:08:53 +0300
commitfc4d53e2ea6b41440e37caf32d2fd236d0f58c93 (patch)
treebe400bc7033d3f198978ad04c05c14f15b8c5324 /deps/aro/SymbolStack.zig
parent0f1652dc603ad43be733cfdd721cedf38d9e45d9 (diff)
parent5792570197f44b2c7599fb756f5c1e9d59bd0a9a (diff)
downloadzig-fc4d53e2ea6b41440e37caf32d2fd236d0f58c93.tar.gz
zig-fc4d53e2ea6b41440e37caf32d2fd236d0f58c93.zip
Merge pull request #17221 from Vexu/aro-translate-c
Aro translate-c
Diffstat (limited to 'deps/aro/SymbolStack.zig')
-rw-r--r--deps/aro/SymbolStack.zig375
1 files changed, 375 insertions, 0 deletions
diff --git a/deps/aro/SymbolStack.zig b/deps/aro/SymbolStack.zig
new file mode 100644
index 0000000000..dc32c14acb
--- /dev/null
+++ b/deps/aro/SymbolStack.zig
@@ -0,0 +1,375 @@
+const std = @import("std");
+const mem = std.mem;
+const Allocator = mem.Allocator;
+const assert = std.debug.assert;
+const Tree = @import("Tree.zig");
+const Token = Tree.Token;
+const TokenIndex = Tree.TokenIndex;
+const NodeIndex = Tree.NodeIndex;
+const Type = @import("Type.zig");
+const Parser = @import("Parser.zig");
+const Value = @import("Value.zig");
+const StringId = @import("StringInterner.zig").StringId;
+
+const SymbolStack = @This();
+
+pub const Symbol = struct {
+ name: StringId,
+ ty: Type,
+ tok: TokenIndex,
+ node: NodeIndex = .none,
+ kind: Kind,
+ val: Value,
+};
+
+pub const Kind = enum {
+ typedef,
+ @"struct",
+ @"union",
+ @"enum",
+ decl,
+ def,
+ enumeration,
+ constexpr,
+};
+
+syms: std.MultiArrayList(Symbol) = .{},
+scopes: std.ArrayListUnmanaged(u32) = .{},
+
+pub fn deinit(s: *SymbolStack, gpa: Allocator) void {
+ s.syms.deinit(gpa);
+ s.scopes.deinit(gpa);
+ s.* = undefined;
+}
+
+pub fn scopeEnd(s: SymbolStack) u32 {
+ if (s.scopes.items.len == 0) return 0;
+ return s.scopes.items[s.scopes.items.len - 1];
+}
+
+pub fn pushScope(s: *SymbolStack, p: *Parser) !void {
+ try s.scopes.append(p.pp.comp.gpa, @intCast(s.syms.len));
+}
+
+pub fn popScope(s: *SymbolStack) void {
+ s.syms.len = s.scopes.pop();
+}
+
+pub fn findTypedef(s: *SymbolStack, p: *Parser, name: StringId, name_tok: TokenIndex, no_type_yet: bool) !?Symbol {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ var i = s.syms.len;
+ while (i > 0) {
+ i -= 1;
+ switch (kinds[i]) {
+ .typedef => if (names[i] == name) return s.syms.get(i),
+ .@"struct" => if (names[i] == name) {
+ if (no_type_yet) return null;
+ try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok));
+ return s.syms.get(i);
+ },
+ .@"union" => if (names[i] == name) {
+ if (no_type_yet) return null;
+ try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok));
+ return s.syms.get(i);
+ },
+ .@"enum" => if (names[i] == name) {
+ if (no_type_yet) return null;
+ try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok));
+ return s.syms.get(i);
+ },
+ .def, .decl, .constexpr => if (names[i] == name) return null,
+ else => {},
+ }
+ }
+ return null;
+}
+
+pub fn findSymbol(s: *SymbolStack, name: StringId) ?Symbol {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ var i = s.syms.len;
+ while (i > 0) {
+ i -= 1;
+ switch (kinds[i]) {
+ .def, .decl, .enumeration, .constexpr => if (names[i] == name) return s.syms.get(i),
+ else => {},
+ }
+ }
+ return null;
+}
+
+pub fn findTag(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ kind: Token.Id,
+ name_tok: TokenIndex,
+ next_tok_id: Token.Id,
+) !?Symbol {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ // `tag Name;` should always result in a new type if in a new scope.
+ const end = if (next_tok_id == .semicolon) s.scopeEnd() else 0;
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .@"enum" => if (names[i] == name) {
+ if (kind == .keyword_enum) return s.syms.get(i);
+ break;
+ },
+ .@"struct" => if (names[i] == name) {
+ if (kind == .keyword_struct) return s.syms.get(i);
+ break;
+ },
+ .@"union" => if (names[i] == name) {
+ if (kind == .keyword_union) return s.syms.get(i);
+ break;
+ },
+ else => {},
+ }
+ } else return null;
+
+ if (i < s.scopeEnd()) return null;
+ try p.errStr(.wrong_tag, name_tok, p.tokSlice(name_tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return null;
+}
+
+pub fn defineTypedef(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ ty: Type,
+ tok: TokenIndex,
+ node: NodeIndex,
+) !void {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .typedef => if (names[i] == name) {
+ const prev_ty = s.syms.items(.ty)[i];
+ if (ty.eql(prev_ty, p.pp.comp, true)) break;
+ try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev_ty));
+ const previous_tok = s.syms.items(.tok)[i];
+ if (previous_tok != 0) try p.errTok(.previous_definition, previous_tok);
+ break;
+ },
+ else => {},
+ }
+ }
+ try s.syms.append(p.pp.comp.gpa, .{
+ .kind = .typedef,
+ .name = name,
+ .tok = tok,
+ .ty = ty,
+ .node = node,
+ .val = .{},
+ });
+}
+
+pub fn defineSymbol(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ ty: Type,
+ tok: TokenIndex,
+ node: NodeIndex,
+ val: Value,
+ constexpr: bool,
+) !void {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .enumeration => if (names[i] == name) {
+ try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ break;
+ },
+ .decl => if (names[i] == name) {
+ const prev_ty = s.syms.items(.ty)[i];
+ if (!ty.eql(prev_ty, p.pp.comp, true)) { // TODO adjusted equality check
+ try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ }
+ break;
+ },
+ .def, .constexpr => if (names[i] == name) {
+ try p.errStr(.redefinition, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ break;
+ },
+ else => {},
+ }
+ }
+ try s.syms.append(p.pp.comp.gpa, .{
+ .kind = if (constexpr) .constexpr else .def,
+ .name = name,
+ .tok = tok,
+ .ty = ty,
+ .node = node,
+ .val = val,
+ });
+}
+
+pub fn declareSymbol(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ ty: Type,
+ tok: TokenIndex,
+ node: NodeIndex,
+) !void {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .enumeration => if (names[i] == name) {
+ try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ break;
+ },
+ .decl => if (names[i] == name) {
+ const prev_ty = s.syms.items(.ty)[i];
+ if (!ty.eql(prev_ty, p.pp.comp, true)) { // TODO adjusted equality check
+ try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ }
+ break;
+ },
+ .def, .constexpr => if (names[i] == name) {
+ const prev_ty = s.syms.items(.ty)[i];
+ if (!ty.eql(prev_ty, p.pp.comp, true)) { // TODO adjusted equality check
+ try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ break;
+ }
+ return;
+ },
+ else => {},
+ }
+ }
+ try s.syms.append(p.pp.comp.gpa, .{
+ .kind = .decl,
+ .name = name,
+ .tok = tok,
+ .ty = ty,
+ .node = node,
+ .val = .{},
+ });
+}
+
+pub fn defineParam(s: *SymbolStack, p: *Parser, name: StringId, ty: Type, tok: TokenIndex) !void {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .enumeration, .decl, .def, .constexpr => if (names[i] == name) {
+ try p.errStr(.redefinition_of_parameter, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ break;
+ },
+ else => {},
+ }
+ }
+ if (ty.is(.fp16) and !p.comp.hasHalfPrecisionFloatABI()) {
+ try p.errStr(.suggest_pointer_for_invalid_fp16, tok, "parameters");
+ }
+ try s.syms.append(p.pp.comp.gpa, .{
+ .kind = .def,
+ .name = name,
+ .tok = tok,
+ .ty = ty,
+ .val = .{},
+ });
+}
+
+pub fn defineTag(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ kind: Token.Id,
+ tok: TokenIndex,
+) !?Symbol {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .@"enum" => if (names[i] == name) {
+ if (kind == .keyword_enum) return s.syms.get(i);
+ try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return null;
+ },
+ .@"struct" => if (names[i] == name) {
+ if (kind == .keyword_struct) return s.syms.get(i);
+ try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return null;
+ },
+ .@"union" => if (names[i] == name) {
+ if (kind == .keyword_union) return s.syms.get(i);
+ try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return null;
+ },
+ else => {},
+ }
+ }
+ return null;
+}
+
+pub fn defineEnumeration(
+ s: *SymbolStack,
+ p: *Parser,
+ name: StringId,
+ ty: Type,
+ tok: TokenIndex,
+ val: Value,
+) !void {
+ const kinds = s.syms.items(.kind);
+ const names = s.syms.items(.name);
+ const end = s.scopeEnd();
+ var i = s.syms.len;
+ while (i > end) {
+ i -= 1;
+ switch (kinds[i]) {
+ .enumeration => if (names[i] == name) {
+ try p.errStr(.redefinition, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return;
+ },
+ .decl, .def, .constexpr => if (names[i] == name) {
+ try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
+ try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
+ return;
+ },
+ else => {},
+ }
+ }
+ try s.syms.append(p.pp.comp.gpa, .{
+ .kind = .enumeration,
+ .name = name,
+ .tok = tok,
+ .ty = ty,
+ .val = val,
+ });
+}