Skip to content

Commit

Permalink
Merge pull request #7628 from roc-lang/parse-s-expr
Browse files Browse the repository at this point in the history
Various changes
  • Loading branch information
lukewilliamboswell authored Feb 22, 2025
2 parents 1620ed0 + 2648141 commit 5d68959
Show file tree
Hide file tree
Showing 33 changed files with 390 additions and 589 deletions.
4 changes: 2 additions & 2 deletions crates/cli/tests/test-projects/issue7461.roc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ new_scatter = \{ data, orientation ? Vertical, name ? ""} ->
}
)

# CHANING ANYHTING IN HERE SEEMS TO "FIX" IT
# CHANING ANYTHING IN HERE SEEMS TO "FIX" IT
scatter_to_str : Trace x -> Str where x implements Inspect
scatter_to_str = \@Trace inner ->

Expand All @@ -62,4 +62,4 @@ new_marker : {} -> Result Marker _
new_marker = \{} -> Ok (@Marker {})

marker_to_str : Marker -> Str
marker_to_str = \_ -> ""
marker_to_str = \_ -> ""
14 changes: 7 additions & 7 deletions crates/glue/writing_a_glue_plugin.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Writing a glue plugin

In order to write a platform, the language the platform is written in must know how to interoperate with Roc. As Roc is statically typed, the required FFI wrapper code must be tailored to the datatypes that form the FFI boundry between the host and the Roc application. Handily, the `roc glue` subcommand will take these types as defined in a `platform.roc` file and turn them into layout information. A glue plugin then in turn uses this to generate the appropriate source code in a target language. This layout information comes in the form of a data structure that requires some additional explanation.
In order to write a platform, the language the platform is written in must know how to interoperate with Roc. As Roc is statically typed, the required FFI wrapper code must be tailored to the datatypes that form the FFI boundary between the host and the Roc application. Handily, the `roc glue` subcommand will take these types as defined in a `platform.roc` file and turn them into layout information. A glue plugin then in turn uses this to generate the appropriate source code in a target language. This layout information comes in the form of a data structure that requires some additional explanation.

- [Writing a glue plugin](#writing-a-glue-plugin)
- [The Types data structure](#the-types-data-structure)
Expand Down Expand Up @@ -30,7 +30,7 @@ In order to write a platform, the language the platform is written in must know

# The Types data structure

`Types` is a data structure that stores the layout information of all types on the host-application FFI boundry for a specific architecture. This includes these types' size, alignment, order of declaration, and their `Shape`.
`Types` is a data structure that stores the layout information of all types on the host-application FFI boundary for a specific architecture. This includes these types' size, alignment, order of declaration, and their `Shape`.

# The Shape data structure

Expand All @@ -51,7 +51,7 @@ A number type. Either a signed integer (I8 through I128), an unsigned integer (U
## RocStr, RocList, RocDict, RocSet, RocBox

Roc builtin datatypes. The Roc compiler is planned to expose parts of the standard library to glue code via C FFI to avoid having the reimplement them by hand in every host language. In the meantime:
- The authoratitive Zig implementations for Roc builtins can be found under `crates/compiler/builtins/bitcode/src`. These are more made for use by the compiler, and thus are better used for reference than for human use.
- The authoritative Zig implementations for Roc builtins can be found under `crates/compiler/builtins/bitcode/src`. These are more made for use by the compiler, and thus are better used for reference than for human use.
- Rust implementations of the `Str`, `List`, and `Box` datatypes can be found under `crates/roc_std`. These are made for use by humans, and as such are a better example for what their wrapper APIs might look like. Do note that these are not guaranteed to be in sync with their Zig implementations.

## Struct
Expand Down Expand Up @@ -154,7 +154,7 @@ Color : [Red, Green, Blue]
```roc
# shape reported by `roc glue`
TagUnion (Enumeration {
name: "Expr",
name: "Expr",
size: 1,
tags: ["Blue", "Green", "Red"]
})
Expand Down Expand Up @@ -343,7 +343,7 @@ ConsList : [
```roc
# shape reported by `roc glue`
TagUnion (NullableUnwrapped {
name: "ConsList",
name: "ConsList",
nonNullPayload: (@TypeId 3), # == TagUnionPayload { name: ConsList_Cons, .. }
nonNullTag: "Cons",
nullTag: "Nil",
Expand Down Expand Up @@ -418,7 +418,7 @@ Color [
name: "Color_Rgb",
fields: (HasNoClosure [
# `@TypeId 1` == `Num U8`
{id: (@TypeId 1), name: "0"},
{id: (@TypeId 1), name: "0"},
{id: (@TypeId 1), name: "1"},
{id: (@TypeId 1), name: "2"}
]),
Expand Down Expand Up @@ -447,4 +447,4 @@ TODO

## RecursivePointer

(TODO: a `RecursivePointer` causes no code to be generated in `RustGlue.roc`, and is otherwise always treated as an instance of the type it's "pointing to", with no pointer indirection like the name implies. Is this shape vestigial?)
(TODO: a `RecursivePointer` causes no code to be generated in `RustGlue.roc`, and is otherwise always treated as an instance of the type it's "pointing to", with no pointer indirection like the name implies. Is this shape vestigial?)
4 changes: 2 additions & 2 deletions src/README.fuzzing.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ If the test case is complex or interesting, it likely is worthwhile to add a sna

For better fuzzing performance you will want to modify `std.mem.backend_can_use_eql_bytes` to return false, otherwise AFL++ will not be able to observe char-by-char string comparisons and its fuzzing capabilities will be greatly reduced.

This means modifying your copy of the Zig stdlib. If you have ZLS you can simply write `std.mem` anywhere in your code and goto definiton, otherwise you can invoke `zig env` and modify `$std_dir/mem.zig`.
This means modifying your copy of the Zig stdlib. If you have ZLS you can simply write `std.mem` anywhere in your code and goto definition, otherwise you can invoke `zig env` and modify `$std_dir/mem.zig`.

**Also don't forget to revert this change after you're done!**

## Advanced Usage

afl++ has a ton of bells and whistle to get way more performance and better results out of it.
The largest one is probably [running multiple copies of afl (preferrably with different configs)](https://aflplus.plus/docs/fuzzing_in_depth/#c-using-multiple-cores) to use all your compute power.
The largest one is probably [running multiple copies of afl (preferably with different configs)](https://aflplus.plus/docs/fuzzing_in_depth/#c-using-multiple-cores) to use all your compute power.

Probably the largest other gain is in keeping around and managing a corpus of examples.
This enables the fuzzer to build up more and more information about the target executable of different execution sessions.
Expand Down
3 changes: 0 additions & 3 deletions src/base.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ pub const Ident = @import("base/Ident.zig");
pub const Module = @import("base/Module.zig");
pub const Region = @import("base/Region.zig");
pub const Package = @import("base/Package.zig");
pub const TagName = @import("base/TagName.zig");
pub const FieldName = @import("base/FieldName.zig");
pub const ModuleEnv = @import("base/ModuleEnv.zig");
pub const TypeVarName = @import("base/TypeVarName.zig");
pub const StringLiteral = @import("base/StringLiteral.zig");

pub const Recursive = enum {
Expand Down
17 changes: 0 additions & 17 deletions src/base/FieldName.zig

This file was deleted.

12 changes: 4 additions & 8 deletions src/base/Ident.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,15 @@ pub const Store = struct {
exposing_modules: std.ArrayList(Module.Idx),
next_unique_name: u32,

pub fn init(allocator: std.mem.Allocator) Store {
pub fn init(arena: *std.heap.ArenaAllocator) Store {
return Store{
.interner = SmallStringInterner.init(allocator),
.exposing_modules = std.ArrayList(Module.Idx).init(allocator),
.interner = SmallStringInterner.init(arena),
// error: expected type 'heap.arena_allocator.ArenaAllocator', found '*heap.arena_allocator.ArenaAllocator'
.exposing_modules = std.ArrayList(Module.Idx).init(arena.allocator()),
.next_unique_name = 0,
};
}

pub fn deinit(self: *Store) void {
self.interner.deinit();
self.exposing_modules.deinit();
}

pub fn insert(self: *Store, ident: Ident, region: Region) Idx {
const idx = self.interner.insert(ident.raw_text, region);
self.exposing_modules.append(@enumFromInt(0)) catch exitOnOom();
Expand Down
12 changes: 6 additions & 6 deletions src/base/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,28 @@ pub const Idx = List.Idx;
pub const Store = struct {
modules: List,
ident_store: *Ident.Store,
allocator: std.mem.Allocator,
arena: *std.heap.ArenaAllocator,

pub const LookupResult = struct {
module_idx: Idx,
was_present: bool,
};

pub fn init(allocator: std.mem.Allocator, ident_store: *Ident.Store) Store {
var modules = collections.SafeMultiList(Module).init(allocator);
pub fn init(arena: *std.heap.ArenaAllocator, ident_store: *Ident.Store) Store {
var modules = collections.SafeMultiList(Module).init(arena.allocator());
_ = modules.append(Module{
.name = &.{},
.package_shorthand = null,
.is_builtin = false,
.exposed_idents = collections.SafeList(Ident.Idx).init(allocator),
.exposed_idents = collections.SafeList(Ident.Idx).init(arena.allocator()),
});

// TODO: insert builtins automatically?

return Store{
.modules = modules,
.ident_store = ident_store,
.allocator = allocator,
.arena = arena,
};
}

Expand Down Expand Up @@ -109,7 +109,7 @@ pub const Store = struct {
.name = name,
.package_shorthand = package_shorthand,
.is_builtin = false,
.exposed_idents = collections.SafeList(Ident.Idx).init(self.allocator),
.exposed_idents = collections.SafeList(Ident.Idx).init(self.arena.allocator()),
});

return LookupResult{ .module_idx = idx, .was_present = false };
Expand Down
36 changes: 9 additions & 27 deletions src/base/ModuleEnv.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ const problem = @import("../problem.zig");

const Ident = @import("./Ident.zig");
const Module = @import("./Module.zig");
const TagName = @import("./TagName.zig");
const FieldName = @import("./FieldName.zig");
const StringLiteral = @import("./StringLiteral.zig");
const Type = @import("../types/type.zig").Type;

Expand All @@ -22,41 +20,25 @@ const Self = @This();
idents: Ident.Store,
ident_ids_for_slicing: collections.SafeList(Ident.Idx),
modules: Module.Store,
tag_names: TagName.Store,
tag_name_ids_for_slicing: collections.SafeList(TagName.Idx),
field_names: FieldName.Store,
strings: StringLiteral.Store,
problems: std.ArrayList(Problem),
type_store: Type.Store,
arena: *std.heap.ArenaAllocator,

pub fn init(allocator: std.mem.Allocator) Self {
var ident_store = Ident.Store.init(allocator);
pub fn init(arena: *std.heap.ArenaAllocator) Self {
var ident_store = Ident.Store.init(arena);

return Self{
.idents = ident_store,
.ident_ids_for_slicing = collections.SafeList(Ident.Idx).init(allocator),
.modules = Module.Store.init(allocator, &ident_store),
.tag_names = TagName.Store.init(allocator),
.tag_name_ids_for_slicing = collections.SafeList(TagName.Idx).init(allocator),
.field_names = FieldName.Store.init(allocator),
.strings = StringLiteral.Store.init(allocator),
.problems = std.ArrayList(Problem).init(allocator),
.type_store = Type.Store.init(allocator),
.ident_ids_for_slicing = collections.SafeList(Ident.Idx).init(arena.allocator()),
.modules = Module.Store.init(arena, &ident_store),
.strings = StringLiteral.Store.init(arena.allocator()),
.problems = std.ArrayList(Problem).init(arena.allocator()),
.type_store = Type.Store.init(arena.allocator()),
.arena = arena,
};
}

pub fn deinit(self: *Self) void {
self.idents.deinit();
self.ident_ids_for_slicing.deinit();
self.modules.deinit();
self.tag_names.deinit();
self.tag_name_ids_for_slicing.deinit();
self.field_names.deinit();
self.strings.deinit();
self.problems.deinit();
self.type_store.deinit();
}

pub fn addExposedIdentForModule(self: *Self, ident: Ident.Idx, module: Module.Idx) void {
self.modules.addExposedIdent(module, ident, &self.problems);
self.idents.setExposingModule(ident, module);
Expand Down
12 changes: 8 additions & 4 deletions src/base/Region.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ pub fn zero() Region {
};
}

pub fn format(self: *const Region, comptime fmt: []const u8, _: std.fmt.FormatOptions, writer: anytype) void {
pub fn format(self: *const Region, comptime fmt: []const u8, _: std.fmt.FormatOptions, writer: std.io.AnyWriter) !void {
if (fmt.len != 0) {
std.fmt.invalidFmtError(fmt, self);
}

if ((self.start == Position.zero()) and (self.end == Position.zero())) {
if ((self.start.isZero()) and (self.end.isZero())) {
// In tests, it's super common to set all Located values to 0.
// Also in tests, we don't want to bother printing the locations
// because it makes failed assertions much harder to read.
return writer.print("…", .{});
try writer.print("…", .{});
} else {
return writer.print("@{}-{}", .{ self.start.offset, self.end.offset });
try writer.print("@{}-{}", .{ self.start.offset, self.end.offset });
}
}

Expand All @@ -39,4 +39,8 @@ pub const Position = struct {
pub fn zero() Position {
return Position{ .offset = 0 };
}

pub fn isZero(self: Position) bool {
return self.offset == 0;
}
};
17 changes: 0 additions & 17 deletions src/base/TagName.zig

This file was deleted.

17 changes: 0 additions & 17 deletions src/base/TypeVarName.zig

This file was deleted.

Loading

0 comments on commit 5d68959

Please sign in to comment.