Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Labels #284

Merged
merged 5 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

## Added
- Tail call optimization (https://github.com/buzz-language/buzz/issues/9)
- REPL (https://github.com/buzz-language/buzz/issues/17) available by running buzz without any argument
- WASM build (https://github.com/buzz-language/buzz/issues/142) and [web REPL](https://buzz-lang.dev/repl.html)
- Function argument names and object property names can be omitted if the provided value is a named variable with the same name (https://github.com/buzz-language/buzz/issues/204)
Expand Down Expand Up @@ -36,29 +37,35 @@ var value = from {
out result;
}
```
- `recursive_call_limit` build option limit recursive calls (default to 200)
- `recursive_call_limit` build option limit recursive calls
- Compiler will warn about code after a `return` statement
- Compiler will warn about unreferenced imports (https://github.com/buzz-language/buzz/issues/272)
- `namespace` (https://github.com/buzz-language/buzz/issues/271): if a script exports at least one symbol, it has to define a namespace for the script with `namespace mynamespace`
- By default, imported symbols from another script will be under `libprefix.XXXX`
- When importing something, you can still redefine its namespace prefix with `import "..." as mynewnamespace` or remove it altogether with `import "..." _`
- Ranges are now an actual buzz value (https://github.com/buzz-language/buzz/issues/170)
- new `range` type
- new `rg` type
- `myrange.toList()` transforms a range into a list of integers
- `myrange.low` and `myrange.high` to get a range bounds
- works with `foreach`
- Tracing JIT (https://github.com/buzz-language/buzz/issues/134): will look for hot loops and compile them
- `list.fill`
- `std.panic` will panic and print current stack trace
- Loop can have _labels_ that you can `break` or `continue` to (https://github.com/buzz-language/buzz/issues/199)

## Changed
- Map type notation has changed from `{K, V}` to `{K: V}`. Similarly map expression with specified typed went from `{<K, V>, ...}` to `{<K: V>, ...}` (https://github.com/buzz-language/buzz/issues/253)
- `File.readLine`, `File.readAll`, `Socket.readLine`, `Socket.readAll` have now an optional `maxSize` argument
- Tail call optimization (https://github.com/buzz-language/buzz/issues/9). The effect should be limited for recursive calls since the JIT compiler should kick in pretty quickly in those use cases.
- Empty list and map without a specified type resolve to `[any]`/`{any: any}` unless the variable declaration context provides the type (https://github.com/buzz-language/buzz/issues/86)
- Function yield type is now prefixed with `*>`: `fun willYield() > T > Y?` becomes `fun willYield() > T *> Y?` (https://github.com/buzz-language/buzz/issues/257)
- Temporarily disabled `--tree` and `--fmt`. The AST has been completely reworked and those feature will take some work to come back.
- `math.random` removed in favor of `std.random`

## Fixed
- A bunch of crash after reported error. buzz tries to hit a maximum of syntax/compile errors by continuing after an error has been reported. This can lead to unexpected state and crash.
- Trying to resolve a global when only its prefix was provided would result in infinite recursion
- Forbid use of `yield`/`resume`/`resolve` in the global scope
- Would break on unfinished char literal

# 0.3.0 (10-14-2023)
## Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ A small/lightweight statically typed scripting language written in Zig

## How to build and install

_Latest zig version supported: 0.13.0-dev.73+db890dbae_
_Latest zig version supported: 0.13.0-dev.211+6a65561e3_

### Requirements
- Since this is built with Zig, you should be able to build buzz on a wide variety of architectures even though this has only been tested on x86/M1.
Expand Down
135 changes: 39 additions & 96 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn getBuzzPrefix(b: *Build) ![]const u8 {
pub fn build(b: *Build) !void {
// Check minimum zig version
const current_zig = builtin.zig_version;
const min_zig = std.SemanticVersion.parse("0.13.0-dev.73+db890dbae") catch return;
const min_zig = std.SemanticVersion.parse("0.13.0-dev.211+6a65561e3") catch return;
if (current_zig.order(min_zig).compare(.lt)) {
@panic(b.fmt("Your Zig version v{} does not meet the minimum build requirement of v{}", .{ current_zig, min_zig }));
}
Expand Down Expand Up @@ -273,15 +273,11 @@ pub fn build(b: *Build) !void {
}

includes.appendSlice(&[_][]const u8{
"/usr/local/include",
"/usr/include",
"./vendors/mir",
"./vendors/mimalloc/include",
}) catch unreachable;

llibs.appendSlice(&[_][]const u8{
"/usr/local/lib",
"/usr/lib",
"./vendors/mir",
}) catch unreachable;

Expand All @@ -298,33 +294,9 @@ pub fn build(b: *Build) !void {
else
null;

// If macOS, add homebrew paths
if (builtin.os.tag == .macos) {
const result = std.ChildProcess.run(
.{
.allocator = b.allocator,
.argv = &[_][]const u8{ "brew", "--prefix" },
},
) catch null;

const prefix = if (result) |r|
std.mem.trim(u8, r.stdout, "\n")
else
std.posix.getenv("HOMEBREW_PREFIX") orelse "/opt/homebrew";

var include = std.ArrayList(u8).init(b.allocator);
include.writer().print("{s}{s}include", .{ prefix, std.fs.path.sep_str }) catch unreachable;

var lib = std.ArrayList(u8).init(b.allocator);
lib.writer().print("{s}{s}lib", .{ prefix, std.fs.path.sep_str }) catch unreachable;

includes.append(include.items) catch unreachable;
llibs.append(lib.items) catch unreachable;
}

var exe = b.addExecutable(.{
.name = "buzz",
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = build_mode,
});
Expand All @@ -349,10 +321,10 @@ pub fn build(b: *Build) !void {
b.step("run", "run buzz").dependOn(&run_exe.step);

for (includes.items) |include| {
exe.addIncludePath(.{ .path = include });
exe.addIncludePath(b.path(include));
}
for (llibs.items) |lib| {
exe.addLibraryPath(.{ .path = lib });
exe.addLibraryPath(b.path(lib));
}
for (sys_libs.items) |slib| {
// FIXME: if mir is linked as static library (libmir.a), here also need to link libc
Expand All @@ -367,20 +339,22 @@ pub fn build(b: *Build) !void {

if (!is_wasm) {
// Building buzz api library
var lib = b.addSharedLibrary(.{
.name = "buzz",
.root_source_file = .{ .path = "src/buzz_api.zig" },
.target = target,
.optimize = build_mode,
});
var lib = b.addSharedLibrary(
.{
.name = "buzz",
.root_source_file = b.path("src/buzz_api.zig"),
.target = target,
.optimize = build_mode,
},
);

b.installArtifact(lib);

for (includes.items) |include| {
lib.addIncludePath(.{ .path = include });
lib.addIncludePath(b.path(include));
}
for (llibs.items) |llib| {
lib.addLibraryPath(.{ .path = llib });
lib.addLibraryPath(b.path(llib));
}
for (sys_libs.items) |slib| {
lib.linkSystemLibrary(slib);
Expand All @@ -403,6 +377,7 @@ pub fn build(b: *Build) !void {
lib.linkSystemLibrary("bcrypt");
}
}

// So that JIT compiled function can reference buzz_api
exe.linkLibrary(lib);
if (lib_linenoise) |ln| {
Expand Down Expand Up @@ -440,8 +415,16 @@ pub fn build(b: *Build) !void {
for (libraries) |library| {
// Copy buzz definitions
const step = b.addInstallLibFile(
.{ .path = b.fmt("src/lib/{s}.buzz", .{library.name}) },
b.fmt("buzz/{s}.buzz", .{library.name}),
b.path(
b.fmt(
"src/lib/{s}.buzz",
.{library.name},
),
),
b.fmt(
"buzz/{s}.buzz",
.{library.name},
),
);
install_step.dependOn(&step.step);

Expand All @@ -451,7 +434,7 @@ pub fn build(b: *Build) !void {

var std_lib = b.addSharedLibrary(.{
.name = library.name,
.root_source_file = .{ .path = library.path.? },
.root_source_file = b.path(library.path.?),
.target = target,
.optimize = build_mode,
});
Expand All @@ -462,10 +445,10 @@ pub fn build(b: *Build) !void {

// No need to link anything when building for wasm since everything is static
for (includes.items) |include| {
std_lib.addIncludePath(.{ .path = include });
std_lib.addIncludePath(b.path(include));
}
for (llibs.items) |llib| {
std_lib.addLibraryPath(.{ .path = llib });
std_lib.addLibraryPath(b.path(llib));
}
for (sys_libs.items) |slib| {
std_lib.linkSystemLibrary(slib);
Expand All @@ -487,33 +470,22 @@ pub fn build(b: *Build) !void {
std_lib.linkLibrary(lib);
std_lib.root_module.addImport("build_options", build_option_module);

// Adds `$BUZZ_PATH/lib` and `/usr/local/lib/buzz` as search path for other shared lib referenced by this one (libbuzz.dylib most of the time)
std_lib.addRPath(
.{
.path = b.fmt(
"{s}" ++ std.fs.path.sep_str ++ "lib/buzz",
.{try getBuzzPrefix(b)},
),
},
);
std_lib.addRPath(.{ .path = "/usr/local/lib/buzz" });

b.default_step.dependOn(&std_lib.step);

library_steps.append(std_lib) catch unreachable;
}
}

const tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = build_mode,
});
for (includes.items) |include| {
tests.addIncludePath(.{ .path = include });
tests.addIncludePath(b.path(include));
}
for (llibs.items) |llib| {
tests.addLibraryPath(.{ .path = llib });
tests.addLibraryPath(b.path(llib));
}
for (sys_libs.items) |slib| {
tests.linkSystemLibrary(slib);
Expand All @@ -534,7 +506,7 @@ pub fn build(b: *Build) !void {

const test_step = b.step("test", "Run all the tests");
const run_tests = b.addRunArtifact(tests);
run_tests.cwd = Build.LazyPath{ .path = "." };
run_tests.cwd = b.path(".");
run_tests.setEnvironmentVariable("BUZZ_PATH", try getBuzzPrefix(b));
run_tests.step.dependOn(install_step); // wait for libraries to be installed
test_step.dependOn(&run_tests.step);
Expand All @@ -547,15 +519,15 @@ pub fn build(b: *Build) !void {
pub fn buildPcre2(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !*Build.Step.Compile {
const copyFiles = b.addWriteFiles();
copyFiles.addCopyFileToSource(
.{ .path = "vendors/pcre2/src/config.h.generic" },
b.path("vendors/pcre2/src/config.h.generic"),
"vendors/pcre2/src/config.h",
);
copyFiles.addCopyFileToSource(
.{ .path = "vendors/pcre2/src/pcre2.h.generic" },
b.path("vendors/pcre2/src/pcre2.h.generic"),
"vendors/pcre2/src/pcre2.h",
);
copyFiles.addCopyFileToSource(
.{ .path = "vendors/pcre2/src/pcre2_chartables.c.dist" },
b.path("vendors/pcre2/src/pcre2_chartables.c.dist"),
"vendors/pcre2/src/pcre2_chartables.c",
);

Expand All @@ -564,7 +536,7 @@ pub fn buildPcre2(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin
.target = target,
.optimize = optimize,
});
lib.addIncludePath(.{ .path = "src" });
lib.addIncludePath(b.path("src"));
lib.addCSourceFiles(
.{
.files = &.{
Expand Down Expand Up @@ -619,38 +591,9 @@ pub fn buildMimalloc(b: *Build, target: Build.ResolvedTarget, optimize: std.buil
},
);

lib.addIncludePath(.{ .path = "./vendors/mimalloc/include" });
lib.addIncludePath(b.path("./vendors/mimalloc/include"));
lib.linkLibC();

if (lib.root_module.resolved_target.?.result.os.tag == .macos) {
var macOS_sdk_path = std.ArrayList(u8).init(b.allocator);
try macOS_sdk_path.writer().print(
"{s}/usr/include",
.{
(std.ChildProcess.run(.{
.allocator = b.allocator,
.argv = &.{
"xcrun",
"--show-sdk-path",
},
.cwd = b.pathFromRoot("."),
.expand_arg0 = .expand,
}) catch {
std.debug.print("Warning: failed to get MacOSX sdk path", .{});
unreachable;
}).stdout,
},
);

lib.addSystemIncludePath(.{ .path = macOS_sdk_path.items });
// Github macos-12 runner (https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md).
lib.addSystemIncludePath(.{ .path = "/Applications/Xcode_14.0.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include" });
lib.addSystemIncludePath(.{ .path = "/Library/Developer/CommandLineTools/SDKs/MacOSX14.0.sdk/usr/include" });
lib.addSystemIncludePath(.{ .path = "/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/include" });
lib.addSystemIncludePath(.{ .path = "/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/usr/include" });
lib.addSystemIncludePath(.{ .path = "/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/include" });
}

lib.addCSourceFiles(
.{
.files = &.{
Expand Down Expand Up @@ -690,7 +633,7 @@ pub fn buildLinenoise(b: *Build, target: Build.ResolvedTarget, optimize: std.bui
.optimize = optimize,
});

lib.addIncludePath(.{ .path = "vendors/linenoise" });
lib.addIncludePath(b.path("vendors/linenoise"));
lib.addCSourceFiles(
.{
.files = &.{
Expand Down Expand Up @@ -738,7 +681,7 @@ pub fn buildWasmReplDemo(b: *Build, exe: *Build.Step.Compile) void {
b.getInstallStep().dependOn(&esbuild.step);

const copyRepl = b.addInstallBinFile(
.{ .path = "src/repl.html" },
b.path("src/repl.html"),
"repl.html",
);
b.getInstallStep().dependOn(&copyRepl.step);
Expand Down
7 changes: 5 additions & 2 deletions src/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ pub const Node = struct {
Block: []Node.Index,
BlockExpression: []Node.Index,
Boolean: bool,
Break: void,
Break: ?Node.Index,
Call: Call,
Continue: void,
Continue: ?Node.Index,
Dot: Dot,
DoUntil: WhileDoUntil,
Enum: Enum,
Expand Down Expand Up @@ -458,6 +458,7 @@ pub const For = struct {
condition: Node.Index,
post_loop: []Node.Index,
body: Node.Index,
label: ?TokenIndex,
};

pub const ForEach = struct {
Expand All @@ -466,6 +467,7 @@ pub const ForEach = struct {
value: Node.Index,
body: Node.Index,
key_omitted: bool,
label: ?TokenIndex,
};

pub const Function = struct {
Expand Down Expand Up @@ -697,6 +699,7 @@ pub const VarDeclaration = struct {
pub const WhileDoUntil = struct {
condition: Node.Index,
body: Node.Index,
label: ?TokenIndex,
};

pub const Zdef = struct {
Expand Down
Loading
Loading