Merge branch 'master' into zen_stdlib
commit
06614b3fa0
|
@ -19,5 +19,5 @@ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
|
|||
echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
|
||||
s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
|
||||
touch empty
|
||||
s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
|
||||
s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header="Cache-Control: max-age=0, must-revalidate" --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
|
||||
fi
|
||||
|
|
|
@ -301,6 +301,15 @@ template <class ELFT> void elf::markLive() {
|
|||
// Follow the graph to mark all live sections.
|
||||
doGcSections<ELFT>();
|
||||
|
||||
// If all references to a DSO happen to be weak, the DSO is removed from
|
||||
// DT_NEEDED, which creates dangling shared symbols to non-existent DSO.
|
||||
// We'll replace such symbols with undefined ones to fix it.
|
||||
for (Symbol *Sym : Symtab->getSymbols())
|
||||
if (auto *S = dyn_cast<SharedSymbol>(Sym))
|
||||
if (S->isWeak() && !S->getFile<ELFT>().IsNeeded)
|
||||
replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
|
||||
S->Type);
|
||||
|
||||
// Report garbage-collected sections.
|
||||
if (Config->PrintGcSections)
|
||||
for (InputSectionBase *Sec : InputSections)
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
const std = @import("std");
|
||||
const debug = std.debug;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const HashMap = std.HashMap;
|
||||
|
||||
fn trimStart(slice: []const u8, ch: u8) []const u8 {
|
||||
var i: usize = 0;
|
||||
for (slice) |b| {
|
||||
if (b != '-') break;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return slice[i..];
|
||||
}
|
||||
|
||||
fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
|
||||
if (maybe_set) |set| {
|
||||
for (set) |possible| {
|
||||
if (mem.eql(u8, arg, possible)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Modifies the current argument index during iteration
|
||||
fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
|
||||
allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
|
||||
|
||||
switch (required) {
|
||||
0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
|
||||
1 => {
|
||||
if (*index + 1 >= args.len) {
|
||||
return error.MissingFlagArguments;
|
||||
}
|
||||
|
||||
*index += 1;
|
||||
const arg = args[*index];
|
||||
|
||||
if (!argInAllowedSet(allowed_set, arg)) {
|
||||
return error.ArgumentNotInAllowedSet;
|
||||
}
|
||||
|
||||
return FlagArg { .Single = arg };
|
||||
},
|
||||
else => |needed| {
|
||||
var extra = ArrayList([]const u8).init(allocator);
|
||||
errdefer extra.deinit();
|
||||
|
||||
var j: usize = 0;
|
||||
while (j < needed) : (j += 1) {
|
||||
if (*index + 1 >= args.len) {
|
||||
return error.MissingFlagArguments;
|
||||
}
|
||||
|
||||
*index += 1;
|
||||
const arg = args[*index];
|
||||
|
||||
if (!argInAllowedSet(allowed_set, arg)) {
|
||||
return error.ArgumentNotInAllowedSet;
|
||||
}
|
||||
|
||||
try extra.append(arg);
|
||||
}
|
||||
|
||||
return FlagArg { .Many = extra };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8);
|
||||
|
||||
// A store for querying found flags and positional arguments.
|
||||
pub const Args = struct {
|
||||
flags: HashMapFlags,
|
||||
positionals: ArrayList([]const u8),
|
||||
|
||||
pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
|
||||
var parsed = Args {
|
||||
.flags = HashMapFlags.init(allocator),
|
||||
.positionals = ArrayList([]const u8).init(allocator),
|
||||
};
|
||||
|
||||
var i: usize = 0;
|
||||
next: while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
|
||||
if (arg.len != 0 and arg[0] == '-') {
|
||||
// TODO: hashmap, although the linear scan is okay for small argument sets as is
|
||||
for (spec) |flag| {
|
||||
if (mem.eql(u8, arg, flag.name)) {
|
||||
const flag_name_trimmed = trimStart(flag.name, '-');
|
||||
const flag_args = readFlagArguments(allocator, args, flag.required, flag.allowed_set, &i) catch |err| {
|
||||
switch (err) {
|
||||
error.ArgumentNotInAllowedSet => {
|
||||
std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
|
||||
std.debug.warn("allowed options are ");
|
||||
for (??flag.allowed_set) |possible| {
|
||||
std.debug.warn("'{}' ", possible);
|
||||
}
|
||||
std.debug.warn("\n");
|
||||
},
|
||||
error.MissingFlagArguments => {
|
||||
std.debug.warn("missing argument for flag: {}\n", arg);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
if (flag.mergable) {
|
||||
var prev =
|
||||
if (parsed.flags.get(flag_name_trimmed)) |entry|
|
||||
entry.value.Many
|
||||
else
|
||||
ArrayList([]const u8).init(allocator);
|
||||
|
||||
// MergeN creation disallows 0 length flag entry (doesn't make sense)
|
||||
switch (flag_args) {
|
||||
FlagArg.None => unreachable,
|
||||
FlagArg.Single => |inner| try prev.append(inner),
|
||||
FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
|
||||
}
|
||||
|
||||
_ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
|
||||
} else {
|
||||
_ = try parsed.flags.put(flag_name_trimmed, flag_args);
|
||||
}
|
||||
|
||||
continue :next;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Better errors with context, global error state and return is sufficient.
|
||||
std.debug.warn("could not match flag: {}\n", arg);
|
||||
return error.UnknownFlag;
|
||||
} else {
|
||||
try parsed.positionals.append(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
pub fn deinit(self: &Args) void {
|
||||
self.flags.deinit();
|
||||
self.positionals.deinit();
|
||||
}
|
||||
|
||||
// e.g. --help
|
||||
pub fn present(self: &Args, name: []const u8) bool {
|
||||
return self.flags.contains(name);
|
||||
}
|
||||
|
||||
// e.g. --name value
|
||||
pub fn single(self: &Args, name: []const u8) ?[]const u8 {
|
||||
if (self.flags.get(name)) |entry| {
|
||||
switch (entry.value) {
|
||||
FlagArg.Single => |inner| { return inner; },
|
||||
else => @panic("attempted to retrieve flag with wrong type"),
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. --names value1 value2 value3
|
||||
pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
|
||||
if (self.flags.get(name)) |entry| {
|
||||
switch (entry.value) {
|
||||
FlagArg.Many => |inner| { return inner.toSliceConst(); },
|
||||
else => @panic("attempted to retrieve flag with wrong type"),
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Arguments for a flag. e.g. arg1, arg2 in `--command arg1 arg2`.
|
||||
const FlagArg = union(enum) {
|
||||
None,
|
||||
Single: []const u8,
|
||||
Many: ArrayList([]const u8),
|
||||
};
|
||||
|
||||
// Specification for how a flag should be parsed.
|
||||
pub const Flag = struct {
|
||||
name: []const u8,
|
||||
required: usize,
|
||||
mergable: bool,
|
||||
allowed_set: ?[]const []const u8,
|
||||
|
||||
pub fn Bool(comptime name: []const u8) Flag {
|
||||
return ArgN(name, 0);
|
||||
}
|
||||
|
||||
pub fn Arg1(comptime name: []const u8) Flag {
|
||||
return ArgN(name, 1);
|
||||
}
|
||||
|
||||
pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
|
||||
return Flag {
|
||||
.name = name,
|
||||
.required = n,
|
||||
.mergable = false,
|
||||
.allowed_set = null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ArgMergeN(comptime name: []const u8, comptime n: usize) Flag {
|
||||
if (n == 0) {
|
||||
@compileError("n must be greater than 0");
|
||||
}
|
||||
|
||||
return Flag {
|
||||
.name = name,
|
||||
.required = n,
|
||||
.mergable = true,
|
||||
.allowed_set = null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
|
||||
return Flag {
|
||||
.name = name,
|
||||
.required = 1,
|
||||
.mergable = false,
|
||||
.allowed_set = set,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
test "parse arguments" {
|
||||
const spec1 = comptime []const Flag {
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--init"),
|
||||
Flag.Arg1("--build-file"),
|
||||
Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
|
||||
Flag.ArgN("--pkg-begin", 2),
|
||||
Flag.ArgMergeN("--object", 1),
|
||||
Flag.ArgN("--library", 1),
|
||||
};
|
||||
|
||||
const cliargs = []const []const u8 {
|
||||
"build",
|
||||
"--help",
|
||||
"pos1",
|
||||
"--build-file", "build.zig",
|
||||
"--object", "obj1",
|
||||
"--object", "obj2",
|
||||
"--library", "lib1",
|
||||
"--library", "lib2",
|
||||
"--color", "on",
|
||||
"pos2",
|
||||
};
|
||||
|
||||
var args = try Args.parse(std.debug.global_allocator, spec1, cliargs);
|
||||
|
||||
debug.assert(args.present("help"));
|
||||
debug.assert(!args.present("help2"));
|
||||
debug.assert(!args.present("init"));
|
||||
|
||||
debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
|
||||
debug.assert(mem.eql(u8, ??args.single("color"), "on"));
|
||||
|
||||
const objects = ??args.many("object");
|
||||
debug.assert(mem.eql(u8, objects[0], "obj1"));
|
||||
debug.assert(mem.eql(u8, objects[1], "obj2"));
|
||||
|
||||
debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
|
||||
|
||||
const pos = args.positionals.toSliceConst();
|
||||
debug.assert(mem.eql(u8, pos[0], "build"));
|
||||
debug.assert(mem.eql(u8, pos[1], "pos1"));
|
||||
debug.assert(mem.eql(u8, pos[2], "pos2"));
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// Introspection and determination of system libraries needed by zig.
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
|
||||
const warn = std.debug.warn;
|
||||
|
||||
/// Caller must free result
|
||||
pub fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
|
||||
const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
|
||||
errdefer allocator.free(test_zig_dir);
|
||||
|
||||
const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
|
||||
defer allocator.free(test_index_file);
|
||||
|
||||
var file = try os.File.openRead(allocator, test_index_file);
|
||||
file.close();
|
||||
|
||||
return test_zig_dir;
|
||||
}
|
||||
|
||||
/// Caller must free result
|
||||
pub fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
|
||||
const self_exe_path = try os.selfExeDirPath(allocator);
|
||||
defer allocator.free(self_exe_path);
|
||||
|
||||
var cur_path: []const u8 = self_exe_path;
|
||||
while (true) {
|
||||
const test_dir = os.path.dirname(cur_path);
|
||||
|
||||
if (mem.eql(u8, test_dir, cur_path)) {
|
||||
break;
|
||||
}
|
||||
|
||||
return testZigInstallPrefix(allocator, test_dir) catch |err| {
|
||||
cur_path = test_dir;
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
pub fn resolveZigLibDir(allocator: &mem.Allocator) ![]u8 {
|
||||
return findZigLibDir(allocator) catch |err| {
|
||||
warn(
|
||||
\\Unable to find zig lib directory: {}.
|
||||
\\Reinstall Zig or use --zig-install-prefix.
|
||||
\\
|
||||
,
|
||||
@errorName(err)
|
||||
);
|
||||
|
||||
return error.ZigLibDirNotFound;
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -109,6 +109,29 @@ pub const Module = struct {
|
|||
LlvmIr,
|
||||
};
|
||||
|
||||
pub const CliPkg = struct {
|
||||
name: []const u8,
|
||||
path: []const u8,
|
||||
children: ArrayList(&CliPkg),
|
||||
parent: ?&CliPkg,
|
||||
|
||||
pub fn init(allocator: &mem.Allocator, name: []const u8, path: []const u8, parent: ?&CliPkg) !&CliPkg {
|
||||
var pkg = try allocator.create(CliPkg);
|
||||
pkg.name = name;
|
||||
pkg.path = path;
|
||||
pkg.children = ArrayList(&CliPkg).init(allocator);
|
||||
pkg.parent = parent;
|
||||
return pkg;
|
||||
}
|
||||
|
||||
pub fn deinit(self: &CliPkg) void {
|
||||
for (self.children.toSliceConst()) |child| {
|
||||
child.deinit();
|
||||
}
|
||||
self.children.deinit();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
|
||||
kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
|
||||
{
|
||||
|
|
|
@ -467,7 +467,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
|||
fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
|
||||
}
|
||||
}
|
||||
fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
|
||||
fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
|
||||
|
||||
switch (fn_table_entry->fn_inline) {
|
||||
case FnInlineAlways:
|
||||
|
|
23
src/ir.cpp
23
src/ir.cpp
|
@ -11395,7 +11395,19 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
|||
}
|
||||
break;
|
||||
case VarClassRequiredAny:
|
||||
// OK
|
||||
if (casted_init_value->value.special == ConstValSpecialStatic &&
|
||||
casted_init_value->value.type->id == TypeTableEntryIdFn &&
|
||||
casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
|
||||
{
|
||||
var_class_requires_const = true;
|
||||
if (!var->src_is_const && !is_comptime_var) {
|
||||
ErrorMsg *msg = ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("functions marked inline must be stored in const or comptime var"));
|
||||
AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
|
||||
add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -11804,7 +11816,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
|||
}
|
||||
}
|
||||
|
||||
bool comptime_arg = param_decl_node->data.param_decl.is_inline;
|
||||
bool comptime_arg = param_decl_node->data.param_decl.is_inline ||
|
||||
casted_arg->value.type->id == TypeTableEntryIdNumLitInt || casted_arg->value.type->id == TypeTableEntryIdNumLitFloat;
|
||||
|
||||
ConstExprValue *arg_val;
|
||||
|
||||
|
@ -11829,6 +11842,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
|||
var->shadowable = !comptime_arg;
|
||||
|
||||
*next_proto_i += 1;
|
||||
} else if (casted_arg->value.type->id == TypeTableEntryIdNumLitInt ||
|
||||
casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
ir_add_error(ira, casted_arg,
|
||||
buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!comptime_arg) {
|
||||
|
|
33
src/main.cpp
33
src/main.cpp
|
@ -54,7 +54,6 @@ static int usage(const char *arg0) {
|
|||
" --verbose-ir turn on compiler debug output for Zig IR\n"
|
||||
" --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"
|
||||
" --verbose-cimport turn on compiler debug output for C imports\n"
|
||||
" --zig-install-prefix [path] override directory where zig thinks it is installed\n"
|
||||
" -dirafter [dir] same as -isystem but do it last\n"
|
||||
" -isystem [dir] add additional search path for other .h files\n"
|
||||
" -mllvm [arg] additional arguments to forward to LLVM's option processing\n"
|
||||
|
@ -177,6 +176,7 @@ static int find_zig_lib_dir(Buf *out_path) {
|
|||
int err;
|
||||
|
||||
Buf self_exe_path = BUF_INIT;
|
||||
buf_resize(&self_exe_path, 0);
|
||||
if (!(err = os_self_exe_path(&self_exe_path))) {
|
||||
Buf *cur_path = &self_exe_path;
|
||||
|
||||
|
@ -199,23 +199,14 @@ static int find_zig_lib_dir(Buf *out_path) {
|
|||
return ErrorFileNotFound;
|
||||
}
|
||||
|
||||
static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
|
||||
static Buf *resolve_zig_lib_dir(void) {
|
||||
int err;
|
||||
Buf *result = buf_alloc();
|
||||
if (zig_install_prefix_arg == nullptr) {
|
||||
if ((err = find_zig_lib_dir(result))) {
|
||||
fprintf(stderr, "Unable to find zig lib directory. Reinstall Zig or use --zig-install-prefix.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return result;
|
||||
if ((err = find_zig_lib_dir(result))) {
|
||||
fprintf(stderr, "Unable to find zig lib directory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Buf *zig_lib_dir_buf = buf_create_from_str(zig_install_prefix_arg);
|
||||
if (test_zig_install_prefix(zig_lib_dir_buf, result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
fprintf(stderr, "No Zig installation found at prefix: %s\n", zig_install_prefix_arg);
|
||||
exit(EXIT_FAILURE);
|
||||
return result;
|
||||
}
|
||||
|
||||
enum Cmd {
|
||||
|
@ -299,7 +290,6 @@ int main(int argc, char **argv) {
|
|||
const char *libc_include_dir = nullptr;
|
||||
const char *msvc_lib_dir = nullptr;
|
||||
const char *kernel32_lib_dir = nullptr;
|
||||
const char *zig_install_prefix = nullptr;
|
||||
const char *dynamic_linker = nullptr;
|
||||
ZigList<const char *> clang_argv = {0};
|
||||
ZigList<const char *> llvm_argv = {0};
|
||||
|
@ -359,17 +349,12 @@ int main(int argc, char **argv) {
|
|||
} else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {
|
||||
cache_dir = argv[i + 1];
|
||||
i += 1;
|
||||
} else if (i + 1 < argc && strcmp(argv[i], "--zig-install-prefix") == 0) {
|
||||
args.append(argv[i]);
|
||||
i += 1;
|
||||
zig_install_prefix = argv[i];
|
||||
args.append(zig_install_prefix);
|
||||
} else {
|
||||
args.append(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
|
||||
|
||||
Buf *zig_std_dir = buf_alloc();
|
||||
os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir);
|
||||
|
@ -590,8 +575,6 @@ int main(int argc, char **argv) {
|
|||
msvc_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
|
||||
kernel32_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--zig-install-prefix") == 0) {
|
||||
zig_install_prefix = argv[i];
|
||||
} else if (strcmp(arg, "--dynamic-linker") == 0) {
|
||||
dynamic_linker = argv[i];
|
||||
} else if (strcmp(arg, "-isystem") == 0) {
|
||||
|
@ -803,7 +786,7 @@ int main(int argc, char **argv) {
|
|||
full_cache_dir);
|
||||
}
|
||||
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
|
||||
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
|
||||
codegen_set_out_name(g, buf_out_name);
|
||||
|
|
|
@ -28,6 +28,7 @@ pub extern "c" fn unlink(path: &const u8) c_int;
|
|||
pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
|
||||
pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int;
|
||||
pub extern "c" fn fork() c_int;
|
||||
pub extern "c" fn access(path: &const u8, mode: c_uint) c_int;
|
||||
pub extern "c" fn pipe(fds: &c_int) c_int;
|
||||
pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
|
||||
pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;
|
||||
|
|
|
@ -41,6 +41,11 @@ pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64
|
|||
pub const O_LARGEFILE = 0x0000;
|
||||
pub const O_PATH = 0x0000;
|
||||
|
||||
pub const F_OK = 0;
|
||||
pub const X_OK = 1;
|
||||
pub const W_OK = 2;
|
||||
pub const R_OK = 4;
|
||||
|
||||
pub const O_RDONLY = 0x0000; /// open for reading only
|
||||
pub const O_WRONLY = 0x0001; /// open for writing only
|
||||
pub const O_RDWR = 0x0002; /// open for reading and writing
|
||||
|
@ -209,6 +214,10 @@ pub fn fork() usize {
|
|||
return errnoWrap(c.fork());
|
||||
}
|
||||
|
||||
pub fn access(path: &const u8, mode: u32) usize {
|
||||
return errnoWrap(c.access(path, mode));
|
||||
}
|
||||
|
||||
pub fn pipe(fds: &[2]i32) usize {
|
||||
comptime assert(i32.bit_count == c_int.bit_count);
|
||||
return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
|
||||
|
|
|
@ -85,6 +85,47 @@ pub const File = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn access(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
|
||||
const path_with_null = try std.cstr.addNullByte(allocator, path);
|
||||
defer allocator.free(path_with_null);
|
||||
|
||||
if (is_posix) {
|
||||
// mode is ignored and is always F_OK for now
|
||||
const result = posix.access(path_with_null.ptr, posix.F_OK);
|
||||
const err = posix.getErrno(result);
|
||||
if (err > 0) {
|
||||
return switch (err) {
|
||||
posix.EACCES => error.PermissionDenied,
|
||||
posix.EROFS => error.PermissionDenied,
|
||||
posix.ELOOP => error.PermissionDenied,
|
||||
posix.ETXTBSY => error.PermissionDenied,
|
||||
posix.ENOTDIR => error.NotFound,
|
||||
posix.ENOENT => error.NotFound,
|
||||
|
||||
posix.ENAMETOOLONG => error.NameTooLong,
|
||||
posix.EINVAL => error.BadMode,
|
||||
posix.EFAULT => error.BadPathName,
|
||||
posix.EIO => error.Io,
|
||||
posix.ENOMEM => error.SystemResources,
|
||||
else => os.unexpectedErrorPosix(err),
|
||||
};
|
||||
}
|
||||
return true;
|
||||
} else if (is_windows) {
|
||||
if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
windows.ERROR.FILE_NOT_FOUND => error.NotFound,
|
||||
windows.ERROR.ACCESS_DENIED => error.PermissionDenied,
|
||||
else => os.unexpectedErrorWindows(err),
|
||||
};
|
||||
} else {
|
||||
@compileError("TODO implement access for this OS");
|
||||
}
|
||||
}
|
||||
|
||||
/// Upon success, the stream is in an uninitialized state. To continue using it,
|
||||
/// you must use the open() function.
|
||||
|
@ -245,7 +286,9 @@ pub const File = struct {
|
|||
};
|
||||
}
|
||||
|
||||
return stat.mode;
|
||||
// TODO: we should be able to cast u16 to ModeError!u32, making this
|
||||
// explicit cast not necessary
|
||||
return os.FileMode(stat.mode);
|
||||
} else if (is_windows) {
|
||||
return {};
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,11 @@ pub const MAP_STACK = 0x20000;
|
|||
pub const MAP_HUGETLB = 0x40000;
|
||||
pub const MAP_FILE = 0;
|
||||
|
||||
pub const F_OK = 0;
|
||||
pub const X_OK = 1;
|
||||
pub const W_OK = 2;
|
||||
pub const R_OK = 4;
|
||||
|
||||
pub const WNOHANG = 1;
|
||||
pub const WUNTRACED = 2;
|
||||
pub const WSTOPPED = 2;
|
||||
|
@ -705,6 +710,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
|
|||
return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
|
||||
}
|
||||
|
||||
pub fn access(path: &const u8, mode: u32) usize {
|
||||
return syscall2(SYS_access, @ptrToInt(path), mode);
|
||||
}
|
||||
|
||||
pub fn pipe(fd: &[2]i32) usize {
|
||||
return pipe2(fd, 0);
|
||||
}
|
||||
|
|
|
@ -23,3 +23,20 @@ test "makePath, put some files in it, deleteTree" {
|
|||
assert(err == error.PathNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
test "access file" {
|
||||
if (builtin.os == builtin.Os.windows) {
|
||||
return;
|
||||
}
|
||||
|
||||
try os.makePath(a, "os_test_tmp");
|
||||
if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
|
||||
unreachable;
|
||||
} else |err| {
|
||||
assert(err == error.NotFound);
|
||||
}
|
||||
|
||||
try io.writeFile(a, "os_test_tmp/file.txt", "");
|
||||
assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true);
|
||||
try os.deleteTree(a, "os_test_tmp");
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
|
|||
pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
|
||||
dwFlags: DWORD) BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
|
||||
in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
|
||||
in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
|
||||
|
|
457
std/zig/ast.zig
457
std/zig/ast.zig
|
@ -9,38 +9,34 @@ pub const Node = struct {
|
|||
comment: ?&NodeLineComment,
|
||||
|
||||
pub const Id = enum {
|
||||
// Top level
|
||||
Root,
|
||||
VarDecl,
|
||||
Use,
|
||||
ErrorSetDecl,
|
||||
ContainerDecl,
|
||||
StructField,
|
||||
UnionTag,
|
||||
EnumTag,
|
||||
Identifier,
|
||||
AsyncAttribute,
|
||||
FnProto,
|
||||
ParamDecl,
|
||||
Block,
|
||||
TestDecl,
|
||||
|
||||
// Statements
|
||||
VarDecl,
|
||||
Defer,
|
||||
Comptime,
|
||||
Payload,
|
||||
PointerPayload,
|
||||
PointerIndexPayload,
|
||||
Else,
|
||||
Switch,
|
||||
SwitchCase,
|
||||
SwitchElse,
|
||||
While,
|
||||
For,
|
||||
If,
|
||||
|
||||
// Operators
|
||||
InfixOp,
|
||||
PrefixOp,
|
||||
SuffixOp,
|
||||
GroupedExpression,
|
||||
|
||||
// Control flow
|
||||
Switch,
|
||||
While,
|
||||
For,
|
||||
If,
|
||||
ControlFlowExpression,
|
||||
Suspend,
|
||||
FieldInitializer,
|
||||
|
||||
// Type expressions
|
||||
VarType,
|
||||
ErrorType,
|
||||
FnProto,
|
||||
|
||||
// Primary expressions
|
||||
IntegerLiteral,
|
||||
FloatLiteral,
|
||||
StringLiteral,
|
||||
|
@ -50,180 +46,143 @@ pub const Node = struct {
|
|||
NullLiteral,
|
||||
UndefinedLiteral,
|
||||
ThisLiteral,
|
||||
Unreachable,
|
||||
Identifier,
|
||||
GroupedExpression,
|
||||
BuiltinCall,
|
||||
ErrorSetDecl,
|
||||
ContainerDecl,
|
||||
Asm,
|
||||
Comptime,
|
||||
Block,
|
||||
|
||||
// Misc
|
||||
LineComment,
|
||||
SwitchCase,
|
||||
SwitchElse,
|
||||
Else,
|
||||
Payload,
|
||||
PointerPayload,
|
||||
PointerIndexPayload,
|
||||
StructField,
|
||||
UnionTag,
|
||||
EnumTag,
|
||||
AsmInput,
|
||||
AsmOutput,
|
||||
Unreachable,
|
||||
ErrorType,
|
||||
VarType,
|
||||
BuiltinCall,
|
||||
LineComment,
|
||||
TestDecl,
|
||||
AsyncAttribute,
|
||||
ParamDecl,
|
||||
FieldInitializer,
|
||||
};
|
||||
|
||||
const IdTypePair = struct {
|
||||
id: Id,
|
||||
Type: type,
|
||||
};
|
||||
|
||||
// TODO: When @field exists, we could generate this by iterating over all members of `Id`,
|
||||
// and making an array of `IdTypePair { .id = @field(Id, @memberName(Id, i)), .Type = @field(ast, "Node" ++ @memberName(Id, i)) }`
|
||||
const idTypeTable = []IdTypePair {
|
||||
IdTypePair { .id = Id.Root, .Type = NodeRoot },
|
||||
IdTypePair { .id = Id.Use, .Type = NodeUse },
|
||||
IdTypePair { .id = Id.TestDecl, .Type = NodeTestDecl },
|
||||
|
||||
IdTypePair { .id = Id.VarDecl, .Type = NodeVarDecl },
|
||||
IdTypePair { .id = Id.Defer, .Type = NodeDefer },
|
||||
|
||||
IdTypePair { .id = Id.InfixOp, .Type = NodeInfixOp },
|
||||
IdTypePair { .id = Id.PrefixOp, .Type = NodePrefixOp },
|
||||
IdTypePair { .id = Id.SuffixOp, .Type = NodeSuffixOp },
|
||||
|
||||
IdTypePair { .id = Id.Switch, .Type = NodeSwitch },
|
||||
IdTypePair { .id = Id.While, .Type = NodeWhile },
|
||||
IdTypePair { .id = Id.For, .Type = NodeFor },
|
||||
IdTypePair { .id = Id.If, .Type = NodeIf },
|
||||
IdTypePair { .id = Id.ControlFlowExpression, .Type = NodeControlFlowExpression },
|
||||
IdTypePair { .id = Id.Suspend, .Type = NodeSuspend },
|
||||
|
||||
IdTypePair { .id = Id.VarType, .Type = NodeVarType },
|
||||
IdTypePair { .id = Id.ErrorType, .Type = NodeErrorType },
|
||||
IdTypePair { .id = Id.FnProto, .Type = NodeFnProto },
|
||||
|
||||
IdTypePair { .id = Id.IntegerLiteral, .Type = NodeIntegerLiteral },
|
||||
IdTypePair { .id = Id.FloatLiteral, .Type = NodeFloatLiteral },
|
||||
IdTypePair { .id = Id.StringLiteral, .Type = NodeStringLiteral },
|
||||
IdTypePair { .id = Id.MultilineStringLiteral, .Type = NodeMultilineStringLiteral },
|
||||
IdTypePair { .id = Id.CharLiteral, .Type = NodeCharLiteral },
|
||||
IdTypePair { .id = Id.BoolLiteral, .Type = NodeBoolLiteral },
|
||||
IdTypePair { .id = Id.NullLiteral, .Type = NodeNullLiteral },
|
||||
IdTypePair { .id = Id.UndefinedLiteral, .Type = NodeUndefinedLiteral },
|
||||
IdTypePair { .id = Id.ThisLiteral, .Type = NodeThisLiteral },
|
||||
IdTypePair { .id = Id.Unreachable, .Type = NodeUnreachable },
|
||||
IdTypePair { .id = Id.Identifier, .Type = NodeIdentifier },
|
||||
IdTypePair { .id = Id.GroupedExpression, .Type = NodeGroupedExpression },
|
||||
IdTypePair { .id = Id.BuiltinCall, .Type = NodeBuiltinCall },
|
||||
IdTypePair { .id = Id.ErrorSetDecl, .Type = NodeErrorSetDecl },
|
||||
IdTypePair { .id = Id.ContainerDecl, .Type = NodeContainerDecl },
|
||||
IdTypePair { .id = Id.Asm, .Type = NodeAsm },
|
||||
IdTypePair { .id = Id.Comptime, .Type = NodeComptime },
|
||||
IdTypePair { .id = Id.Block, .Type = NodeBlock },
|
||||
|
||||
IdTypePair { .id = Id.LineComment, .Type = NodeLineComment },
|
||||
IdTypePair { .id = Id.SwitchCase, .Type = NodeSwitchCase },
|
||||
IdTypePair { .id = Id.SwitchElse, .Type = NodeSwitchElse },
|
||||
IdTypePair { .id = Id.Else, .Type = NodeElse },
|
||||
IdTypePair { .id = Id.Payload, .Type = NodePayload },
|
||||
IdTypePair { .id = Id.PointerPayload, .Type = NodePointerPayload },
|
||||
IdTypePair { .id = Id.PointerIndexPayload, .Type = NodePointerIndexPayload },
|
||||
IdTypePair { .id = Id.StructField, .Type = NodeStructField },
|
||||
IdTypePair { .id = Id.UnionTag, .Type = NodeUnionTag },
|
||||
IdTypePair { .id = Id.EnumTag, .Type = NodeEnumTag },
|
||||
IdTypePair { .id = Id.AsmInput, .Type = NodeAsmInput },
|
||||
IdTypePair { .id = Id.AsmOutput, .Type = NodeAsmOutput },
|
||||
IdTypePair { .id = Id.AsyncAttribute, .Type = NodeAsyncAttribute },
|
||||
IdTypePair { .id = Id.ParamDecl, .Type = NodeParamDecl },
|
||||
IdTypePair { .id = Id.FieldInitializer, .Type = NodeFieldInitializer },
|
||||
};
|
||||
|
||||
pub fn IdToType(comptime id: Id) type {
|
||||
inline for (idTypeTable) |id_type_pair| {
|
||||
if (id == id_type_pair.id)
|
||||
return id_type_pair.Type;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn typeToId(comptime T: type) Id {
|
||||
inline for (idTypeTable) |id_type_pair| {
|
||||
if (T == id_type_pair.Type)
|
||||
return id_type_pair.id;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn iterate(base: &Node, index: usize) ?&Node {
|
||||
return switch (base.id) {
|
||||
Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),
|
||||
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),
|
||||
Id.Use => @fieldParentPtr(NodeUse, "base", base).iterate(index),
|
||||
Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index),
|
||||
Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index),
|
||||
Id.StructField => @fieldParentPtr(NodeStructField, "base", base).iterate(index),
|
||||
Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).iterate(index),
|
||||
Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).iterate(index),
|
||||
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),
|
||||
Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).iterate(index),
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
|
||||
Id.Defer => @fieldParentPtr(NodeDefer, "base", base).iterate(index),
|
||||
Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).iterate(index),
|
||||
Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index),
|
||||
Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).iterate(index),
|
||||
Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).iterate(index),
|
||||
Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
|
||||
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
|
||||
Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index),
|
||||
Id.For => @fieldParentPtr(NodeFor, "base", base).iterate(index),
|
||||
Id.If => @fieldParentPtr(NodeIf, "base", base).iterate(index),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
|
||||
Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).iterate(index),
|
||||
Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).iterate(index),
|
||||
Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).iterate(index),
|
||||
Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).iterate(index),
|
||||
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
|
||||
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
|
||||
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
|
||||
Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).iterate(index),
|
||||
Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).iterate(index),
|
||||
Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).iterate(index),
|
||||
Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).iterate(index),
|
||||
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
|
||||
Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).iterate(index),
|
||||
Id.Asm => @fieldParentPtr(NodeAsm, "base", base).iterate(index),
|
||||
Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).iterate(index),
|
||||
Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).iterate(index),
|
||||
Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index),
|
||||
Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index),
|
||||
Id.VarType => @fieldParentPtr(NodeVarType, "base", base).iterate(index),
|
||||
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
|
||||
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
|
||||
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
|
||||
};
|
||||
inline for (idTypeTable) |id_type_pair| {
|
||||
if (base.id == id_type_pair.id)
|
||||
return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn firstToken(base: &Node) Token {
|
||||
return switch (base.id) {
|
||||
Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),
|
||||
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),
|
||||
Id.Use => @fieldParentPtr(NodeUse, "base", base).firstToken(),
|
||||
Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(),
|
||||
Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(),
|
||||
Id.StructField => @fieldParentPtr(NodeStructField, "base", base).firstToken(),
|
||||
Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).firstToken(),
|
||||
Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).firstToken(),
|
||||
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),
|
||||
Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).firstToken(),
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
|
||||
Id.Defer => @fieldParentPtr(NodeDefer, "base", base).firstToken(),
|
||||
Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).firstToken(),
|
||||
Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(),
|
||||
Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).firstToken(),
|
||||
Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).firstToken(),
|
||||
Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
|
||||
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
|
||||
Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(),
|
||||
Id.For => @fieldParentPtr(NodeFor, "base", base).firstToken(),
|
||||
Id.If => @fieldParentPtr(NodeIf, "base", base).firstToken(),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
|
||||
Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).firstToken(),
|
||||
Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).firstToken(),
|
||||
Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).firstToken(),
|
||||
Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).firstToken(),
|
||||
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
|
||||
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
|
||||
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
|
||||
Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).firstToken(),
|
||||
Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).firstToken(),
|
||||
Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).firstToken(),
|
||||
Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).firstToken(),
|
||||
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
|
||||
Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(),
|
||||
Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(),
|
||||
Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(),
|
||||
Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).firstToken(),
|
||||
Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).firstToken(),
|
||||
Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(),
|
||||
Id.VarType => @fieldParentPtr(NodeVarType, "base", base).firstToken(),
|
||||
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
|
||||
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
|
||||
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
|
||||
};
|
||||
inline for (idTypeTable) |id_type_pair| {
|
||||
if (base.id == id_type_pair.id)
|
||||
return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn lastToken(base: &Node) Token {
|
||||
return switch (base.id) {
|
||||
Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),
|
||||
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),
|
||||
Id.Use => @fieldParentPtr(NodeUse, "base", base).lastToken(),
|
||||
Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(),
|
||||
Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(),
|
||||
Id.StructField => @fieldParentPtr(NodeStructField, "base", base).lastToken(),
|
||||
Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).lastToken(),
|
||||
Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).lastToken(),
|
||||
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),
|
||||
Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).lastToken(),
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
|
||||
Id.Defer => @fieldParentPtr(NodeDefer, "base", base).lastToken(),
|
||||
Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).lastToken(),
|
||||
Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(),
|
||||
Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).lastToken(),
|
||||
Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).lastToken(),
|
||||
Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
|
||||
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(),
|
||||
Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(),
|
||||
Id.For => @fieldParentPtr(NodeFor, "base", base).lastToken(),
|
||||
Id.If => @fieldParentPtr(NodeIf, "base", base).lastToken(),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
|
||||
Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).lastToken(),
|
||||
Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).lastToken(),
|
||||
Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).lastToken(),
|
||||
Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).lastToken(),
|
||||
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
|
||||
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
|
||||
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
|
||||
Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).lastToken(),
|
||||
Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).lastToken(),
|
||||
Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).lastToken(),
|
||||
Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).lastToken(),
|
||||
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
|
||||
Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(),
|
||||
Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(),
|
||||
Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).lastToken(),
|
||||
Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).lastToken(),
|
||||
Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(),
|
||||
Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(),
|
||||
Id.VarType => @fieldParentPtr(NodeVarType, "base", base).lastToken(),
|
||||
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
|
||||
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
|
||||
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
|
||||
};
|
||||
inline for (idTypeTable) |id_type_pair| {
|
||||
if (base.id == id_type_pair.id)
|
||||
return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -255,7 +214,7 @@ pub const NodeVarDecl = struct {
|
|||
eq_token: Token,
|
||||
mut_token: Token,
|
||||
comptime_token: ?Token,
|
||||
extern_token: ?Token,
|
||||
extern_export_token: ?Token,
|
||||
lib_name: ?&Node,
|
||||
type_node: ?&Node,
|
||||
align_node: ?&Node,
|
||||
|
@ -286,7 +245,7 @@ pub const NodeVarDecl = struct {
|
|||
pub fn firstToken(self: &NodeVarDecl) Token {
|
||||
if (self.visib_token) |visib_token| return visib_token;
|
||||
if (self.comptime_token) |comptime_token| return comptime_token;
|
||||
if (self.extern_token) |extern_token| return extern_token;
|
||||
if (self.extern_export_token) |extern_export_token| return extern_export_token;
|
||||
assert(self.lib_name == null);
|
||||
return self.mut_token;
|
||||
}
|
||||
|
@ -324,13 +283,13 @@ pub const NodeUse = struct {
|
|||
pub const NodeErrorSetDecl = struct {
|
||||
base: Node,
|
||||
error_token: Token,
|
||||
decls: ArrayList(&NodeIdentifier),
|
||||
decls: ArrayList(&Node),
|
||||
rbrace_token: Token,
|
||||
|
||||
pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < self.decls.len) return &self.decls.at(i).base;
|
||||
if (i < self.decls.len) return self.decls.at(i);
|
||||
i -= self.decls.len;
|
||||
|
||||
return null;
|
||||
|
@ -401,6 +360,7 @@ pub const NodeContainerDecl = struct {
|
|||
|
||||
pub const NodeStructField = struct {
|
||||
base: Node,
|
||||
visib_token: ?Token,
|
||||
name_token: Token,
|
||||
type_expr: &Node,
|
||||
|
||||
|
@ -414,6 +374,7 @@ pub const NodeStructField = struct {
|
|||
}
|
||||
|
||||
pub fn firstToken(self: &NodeStructField) Token {
|
||||
if (self.visib_token) |visib_token| return visib_token;
|
||||
return self.name_token;
|
||||
}
|
||||
|
||||
|
@ -482,18 +443,18 @@ pub const NodeEnumTag = struct {
|
|||
|
||||
pub const NodeIdentifier = struct {
|
||||
base: Node,
|
||||
name_token: Token,
|
||||
token: Token,
|
||||
|
||||
pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: &NodeIdentifier) Token {
|
||||
return self.name_token;
|
||||
return self.token;
|
||||
}
|
||||
|
||||
pub fn lastToken(self: &NodeIdentifier) Token {
|
||||
return self.name_token;
|
||||
return self.token;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -535,8 +496,7 @@ pub const NodeFnProto = struct {
|
|||
params: ArrayList(&Node),
|
||||
return_type: ReturnType,
|
||||
var_args_token: ?Token,
|
||||
extern_token: ?Token,
|
||||
inline_token: ?Token,
|
||||
extern_export_inline_token: ?Token,
|
||||
cc_token: ?Token,
|
||||
async_attr: ?&NodeAsyncAttribute,
|
||||
body_node: ?&Node,
|
||||
|
@ -586,9 +546,8 @@ pub const NodeFnProto = struct {
|
|||
|
||||
pub fn firstToken(self: &NodeFnProto) Token {
|
||||
if (self.visib_token) |visib_token| return visib_token;
|
||||
if (self.extern_token) |extern_token| return extern_token;
|
||||
if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
|
||||
assert(self.lib_name == null);
|
||||
if (self.inline_token) |inline_token| return inline_token;
|
||||
if (self.cc_token) |cc_token| return cc_token;
|
||||
return self.fn_token;
|
||||
}
|
||||
|
@ -717,13 +676,13 @@ pub const NodeComptime = struct {
|
|||
pub const NodePayload = struct {
|
||||
base: Node,
|
||||
lpipe: Token,
|
||||
error_symbol: &NodeIdentifier,
|
||||
error_symbol: &Node,
|
||||
rpipe: Token,
|
||||
|
||||
pub fn iterate(self: &NodePayload, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return &self.error_symbol.base;
|
||||
if (i < 1) return self.error_symbol;
|
||||
i -= 1;
|
||||
|
||||
return null;
|
||||
|
@ -741,14 +700,14 @@ pub const NodePayload = struct {
|
|||
pub const NodePointerPayload = struct {
|
||||
base: Node,
|
||||
lpipe: Token,
|
||||
is_ptr: bool,
|
||||
value_symbol: &NodeIdentifier,
|
||||
ptr_token: ?Token,
|
||||
value_symbol: &Node,
|
||||
rpipe: Token,
|
||||
|
||||
pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return &self.value_symbol.base;
|
||||
if (i < 1) return self.value_symbol;
|
||||
i -= 1;
|
||||
|
||||
return null;
|
||||
|
@ -766,19 +725,19 @@ pub const NodePointerPayload = struct {
|
|||
pub const NodePointerIndexPayload = struct {
|
||||
base: Node,
|
||||
lpipe: Token,
|
||||
is_ptr: bool,
|
||||
value_symbol: &NodeIdentifier,
|
||||
index_symbol: ?&NodeIdentifier,
|
||||
ptr_token: ?Token,
|
||||
value_symbol: &Node,
|
||||
index_symbol: ?&Node,
|
||||
rpipe: Token,
|
||||
|
||||
pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return &self.value_symbol.base;
|
||||
if (i < 1) return self.value_symbol;
|
||||
i -= 1;
|
||||
|
||||
if (self.index_symbol) |index_symbol| {
|
||||
if (i < 1) return &index_symbol.base;
|
||||
if (i < 1) return index_symbol;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -797,14 +756,14 @@ pub const NodePointerIndexPayload = struct {
|
|||
pub const NodeElse = struct {
|
||||
base: Node,
|
||||
else_token: Token,
|
||||
payload: ?&NodePayload,
|
||||
payload: ?&Node,
|
||||
body: &Node,
|
||||
|
||||
pub fn iterate(self: &NodeElse, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -854,7 +813,7 @@ pub const NodeSwitch = struct {
|
|||
pub const NodeSwitchCase = struct {
|
||||
base: Node,
|
||||
items: ArrayList(&Node),
|
||||
payload: ?&NodePointerPayload,
|
||||
payload: ?&Node,
|
||||
expr: &Node,
|
||||
|
||||
pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
|
||||
|
@ -864,7 +823,7 @@ pub const NodeSwitchCase = struct {
|
|||
i -= self.items.len;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -906,7 +865,7 @@ pub const NodeWhile = struct {
|
|||
inline_token: ?Token,
|
||||
while_token: Token,
|
||||
condition: &Node,
|
||||
payload: ?&NodePointerPayload,
|
||||
payload: ?&Node,
|
||||
continue_expr: ?&Node,
|
||||
body: &Node,
|
||||
@"else": ?&NodeElse,
|
||||
|
@ -918,7 +877,7 @@ pub const NodeWhile = struct {
|
|||
i -= 1;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -965,7 +924,7 @@ pub const NodeFor = struct {
|
|||
inline_token: ?Token,
|
||||
for_token: Token,
|
||||
array_expr: &Node,
|
||||
payload: ?&NodePointerIndexPayload,
|
||||
payload: ?&Node,
|
||||
body: &Node,
|
||||
@"else": ?&NodeElse,
|
||||
|
||||
|
@ -976,7 +935,7 @@ pub const NodeFor = struct {
|
|||
i -= 1;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +975,7 @@ pub const NodeIf = struct {
|
|||
base: Node,
|
||||
if_token: Token,
|
||||
condition: &Node,
|
||||
payload: ?&NodePointerPayload,
|
||||
payload: ?&Node,
|
||||
body: &Node,
|
||||
@"else": ?&NodeElse,
|
||||
|
||||
|
@ -1027,7 +986,7 @@ pub const NodeIf = struct {
|
|||
i -= 1;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1048,7 @@ pub const NodeInfixOp = struct {
|
|||
BitXor,
|
||||
BoolAnd,
|
||||
BoolOr,
|
||||
Catch: ?&NodePayload,
|
||||
Catch: ?&Node,
|
||||
Div,
|
||||
EqualEqual,
|
||||
ErrorUnion,
|
||||
|
@ -1117,7 +1076,7 @@ pub const NodeInfixOp = struct {
|
|||
switch (self.op) {
|
||||
InfixOp.Catch => |maybe_payload| {
|
||||
if (maybe_payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
},
|
||||
|
@ -1385,14 +1344,30 @@ pub const NodeControlFlowExpression = struct {
|
|||
rhs: ?&Node,
|
||||
|
||||
const Kind = union(enum) {
|
||||
Break: ?Token,
|
||||
Continue: ?Token,
|
||||
Break: ?&Node,
|
||||
Continue: ?&Node,
|
||||
Return,
|
||||
};
|
||||
|
||||
pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
switch (self.kind) {
|
||||
Kind.Break => |maybe_label| {
|
||||
if (maybe_label) |label| {
|
||||
if (i < 1) return label;
|
||||
i -= 1;
|
||||
}
|
||||
},
|
||||
Kind.Continue => |maybe_label| {
|
||||
if (maybe_label) |label| {
|
||||
if (i < 1) return label;
|
||||
i -= 1;
|
||||
}
|
||||
},
|
||||
Kind.Return => {},
|
||||
}
|
||||
|
||||
if (self.rhs) |rhs| {
|
||||
if (i < 1) return rhs;
|
||||
i -= 1;
|
||||
|
@ -1411,14 +1386,14 @@ pub const NodeControlFlowExpression = struct {
|
|||
}
|
||||
|
||||
switch (self.kind) {
|
||||
Kind.Break => |maybe_blk_token| {
|
||||
if (maybe_blk_token) |blk_token| {
|
||||
return blk_token;
|
||||
Kind.Break => |maybe_label| {
|
||||
if (maybe_label) |label| {
|
||||
return label.lastToken();
|
||||
}
|
||||
},
|
||||
Kind.Continue => |maybe_blk_token| {
|
||||
if (maybe_blk_token) |blk_token| {
|
||||
return blk_token;
|
||||
Kind.Continue => |maybe_label| {
|
||||
if (maybe_label) |label| {
|
||||
return label.lastToken();
|
||||
}
|
||||
},
|
||||
Kind.Return => return self.ltoken,
|
||||
|
@ -1431,14 +1406,14 @@ pub const NodeControlFlowExpression = struct {
|
|||
pub const NodeSuspend = struct {
|
||||
base: Node,
|
||||
suspend_token: Token,
|
||||
payload: ?&NodePayload,
|
||||
payload: ?&Node,
|
||||
body: ?&Node,
|
||||
|
||||
pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return &payload.base;
|
||||
if (i < 1) return payload;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
@ -1646,8 +1621,8 @@ pub const NodeThisLiteral = struct {
|
|||
|
||||
pub const NodeAsmOutput = struct {
|
||||
base: Node,
|
||||
symbolic_name: &NodeIdentifier,
|
||||
constraint: &NodeStringLiteral,
|
||||
symbolic_name: &Node,
|
||||
constraint: &Node,
|
||||
kind: Kind,
|
||||
|
||||
const Kind = union(enum) {
|
||||
|
@ -1658,10 +1633,10 @@ pub const NodeAsmOutput = struct {
|
|||
pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return &self.symbolic_name.base;
|
||||
if (i < 1) return self.symbolic_name;
|
||||
i -= 1;
|
||||
|
||||
if (i < 1) return &self.constraint.base;
|
||||
if (i < 1) return self.constraint;
|
||||
i -= 1;
|
||||
|
||||
switch (self.kind) {
|
||||
|
@ -1692,17 +1667,17 @@ pub const NodeAsmOutput = struct {
|
|||
|
||||
pub const NodeAsmInput = struct {
|
||||
base: Node,
|
||||
symbolic_name: &NodeIdentifier,
|
||||
constraint: &NodeStringLiteral,
|
||||
symbolic_name: &Node,
|
||||
constraint: &Node,
|
||||
expr: &Node,
|
||||
|
||||
pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return &self.symbolic_name.base;
|
||||
if (i < 1) return self.symbolic_name;
|
||||
i -= 1;
|
||||
|
||||
if (i < 1) return &self.constraint.base;
|
||||
if (i < 1) return self.constraint;
|
||||
i -= 1;
|
||||
|
||||
if (i < 1) return self.expr;
|
||||
|
@ -1723,12 +1698,12 @@ pub const NodeAsmInput = struct {
|
|||
pub const NodeAsm = struct {
|
||||
base: Node,
|
||||
asm_token: Token,
|
||||
is_volatile: bool,
|
||||
template: Token,
|
||||
volatile_token: ?Token,
|
||||
template: &Node,
|
||||
//tokens: ArrayList(AsmToken),
|
||||
outputs: ArrayList(&NodeAsmOutput),
|
||||
inputs: ArrayList(&NodeAsmInput),
|
||||
cloppers: ArrayList(&NodeStringLiteral),
|
||||
cloppers: ArrayList(&Node),
|
||||
rparen: Token,
|
||||
|
||||
pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
|
||||
|
@ -1740,7 +1715,7 @@ pub const NodeAsm = struct {
|
|||
if (i < self.inputs.len) return &self.inputs.at(index).base;
|
||||
i -= self.inputs.len;
|
||||
|
||||
if (i < self.cloppers.len) return &self.cloppers.at(index).base;
|
||||
if (i < self.cloppers.len) return self.cloppers.at(index);
|
||||
i -= self.cloppers.len;
|
||||
|
||||
return null;
|
||||
|
|
5202
std/zig/parser.zig
5202
std/zig/parser.zig
File diff suppressed because it is too large
Load Diff
|
@ -94,3 +94,20 @@ test "inline function call" {
|
|||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 { return a + b; }
|
||||
|
||||
|
||||
test "number literal as an argument" {
|
||||
numberLiteralArg(3);
|
||||
comptime numberLiteralArg(3);
|
||||
}
|
||||
|
||||
fn numberLiteralArg(a: var) void {
|
||||
assert(a == 3);
|
||||
}
|
||||
|
||||
test "assign inline fn to const variable" {
|
||||
const a = inlineFn;
|
||||
a();
|
||||
}
|
||||
|
||||
inline fn inlineFn() void { }
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: &tests.CompileErrorContext) void {
|
||||
cases.add("assign inline fn to non-comptime var",
|
||||
\\export fn entry() void {
|
||||
\\ var a = b;
|
||||
\\}
|
||||
\\inline fn b() void { }
|
||||
,
|
||||
".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
|
||||
".tmp_source.zig:4:8: note: declared here");
|
||||
|
||||
cases.add("wrong type passed to @panic",
|
||||
\\export fn entry() void {
|
||||
\\ var e = error.Foo;
|
||||
|
@ -1723,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
|
|||
\\}
|
||||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
|
||||
, ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime");
|
||||
, ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted");
|
||||
|
||||
cases.add("assign too big number to u16",
|
||||
\\export fn foo() void {
|
||||
|
|
Loading…
Reference in New Issue