Merge branch 'c-to-zig'

This commit is contained in:
Andrew Kelley 2017-09-05 18:51:48 -04:00
commit 48c44615a4
21 changed files with 3273 additions and 943 deletions

View File

@ -751,6 +751,7 @@ struct AstNodeContainerDecl {
ZigList<AstNode *> fields;
ZigList<AstNode *> decls;
ContainerLayout layout;
AstNode *init_arg_expr; // enum(T) or struct(endianness)
};
struct AstNodeStructField {
@ -833,7 +834,6 @@ struct AstNode {
enum NodeType type;
size_t line;
size_t column;
uint32_t create_index; // for determinism purposes
ImportTableEntry *owner;
union {
AstNodeRoot root;
@ -1253,6 +1253,7 @@ enum BuiltinFnId {
BuiltinFnIdShrExact,
BuiltinFnIdSetEvalBranchQuota,
BuiltinFnIdAlignCast,
BuiltinFnIdOpaqueType,
};
struct BuiltinFnEntry {
@ -1523,7 +1524,6 @@ struct CodeGen {
LLVMValueRef return_address_fn_val;
LLVMValueRef frame_address_fn_val;
bool error_during_imports;
uint32_t next_node_index;
TypeTableEntry *err_tag_type;
const char **clang_argv;
@ -1859,6 +1859,7 @@ enum IrInstructionId {
IrInstructionIdSetEvalBranchQuota,
IrInstructionIdPtrTypeOf,
IrInstructionIdAlignCast,
IrInstructionIdOpaqueType,
};
struct IrInstruction {
@ -2649,6 +2650,10 @@ struct IrInstructionAlignCast {
IrInstruction *target;
};
struct IrInstructionOpaqueType {
IrInstruction base;
};
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;

View File

@ -1180,7 +1180,8 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
}
}
fn_type_id.return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
fn_type_id.return_type = (fn_proto->return_type == nullptr) ?
g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type);
switch (fn_type_id.return_type->id) {
case TypeTableEntryIdInvalid:
@ -2056,7 +2057,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
for (size_t i = 0; i < fn_proto->params.length; i += 1) {
AstNode *param_node = fn_proto->params.at(i);
assert(param_node->type == NodeTypeParamDecl);
if (buf_len(param_node->data.param_decl.name) == 0) {
if (param_node->data.param_decl.name == nullptr) {
add_node_error(g, param_node, buf_sprintf("missing parameter name"));
}
}
@ -2268,7 +2269,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
{
// if the name is missing, we immediately announce an error
Buf *fn_name = node->data.fn_proto.name;
if (buf_len(fn_name) == 0) {
if (fn_name == nullptr) {
add_node_error(g, node, buf_sprintf("missing function name"));
break;
}
@ -2950,6 +2951,9 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
} else {
param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i);
}
if (param_name == nullptr) {
continue;
}
TypeTableEntry *param_type = param_info->type;
bool is_noalias = param_info->is_noalias;
@ -3163,8 +3167,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
import_entry->line_offsets = tokenization.line_offsets;
import_entry->path = abs_full_path;
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
&g->next_node_index);
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
assert(import_entry->root);
if (g->verbose) {
ast_print(stderr, import_entry->root, 0);

View File

@ -112,16 +112,16 @@ static const char *extern_string(bool is_extern) {
return is_extern ? "extern " : "";
}
static const char *calling_convention_string(CallingConvention cc) {
switch (cc) {
case CallingConventionUnspecified: return "";
case CallingConventionC: return "extern ";
case CallingConventionCold: return "coldcc ";
case CallingConventionNaked: return "nakedcc ";
case CallingConventionStdcall: return "stdcallcc ";
}
zig_unreachable();
}
//static const char *calling_convention_string(CallingConvention cc) {
// switch (cc) {
// case CallingConventionUnspecified: return "";
// case CallingConventionC: return "extern ";
// case CallingConventionCold: return "coldcc ";
// case CallingConventionNaked: return "nakedcc ";
// case CallingConventionStdcall: return "stdcallcc ";
// }
// zig_unreachable();
//}
static const char *inline_string(bool is_inline) {
return is_inline ? "inline " : "";
@ -412,14 +412,17 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
const char *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *inline_str = inline_string(node->data.fn_proto.is_inline);
fprintf(ar->f, "%s%s%sfn ", pub_str, inline_str, extern_str);
print_symbol(ar, node->data.fn_proto.name);
fprintf(ar->f, "%s%s%sfn", pub_str, inline_str, extern_str);
if (node->data.fn_proto.name != nullptr) {
fprintf(ar->f, " ");
print_symbol(ar, node->data.fn_proto.name);
}
fprintf(ar->f, "(");
size_t arg_count = node->data.fn_proto.params.length;
for (size_t arg_i = 0; arg_i < arg_count; arg_i += 1) {
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
assert(param_decl->type == NodeTypeParamDecl);
if (buf_len(param_decl->data.param_decl.name) > 0) {
if (param_decl->data.param_decl.name != nullptr) {
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";
fprintf(ar->f, "%s%s", noalias_str, inline_str);
@ -439,8 +442,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, ")");
AstNode *return_type_node = node->data.fn_proto.return_type;
fprintf(ar->f, " -> ");
render_node_grouped(ar, return_type_node);
if (return_type_node != nullptr) {
fprintf(ar->f, " -> ");
render_node_grouped(ar, return_type_node);
}
break;
}
case NodeTypeFnDef:
@ -651,16 +656,19 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
break;
case NodeTypeContainerDecl:
{
const char *layout_str = layout_string(node->data.container_decl.layout);
const char *container_str = container_string(node->data.container_decl.kind);
fprintf(ar->f, "%s {\n", container_str);
fprintf(ar->f, "%s%s {\n", layout_str, container_str);
ar->indent += ar->indent_size;
for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
AstNode *field_node = node->data.container_decl.fields.at(field_i);
assert(field_node->type == NodeTypeStructField);
print_indent(ar);
print_symbol(ar, field_node->data.struct_field.name);
fprintf(ar->f, ": ");
render_node_grouped(ar, field_node->data.struct_field.type);
if (field_node->data.struct_field.type != nullptr) {
fprintf(ar->f, ": ");
render_node_grouped(ar, field_node->data.struct_field.type);
}
fprintf(ar->f, ",\n");
}
@ -989,146 +997,3 @@ void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size) {
render_node_grouped(&ar, node);
}
static void ast_render_tld_fn(AstRender *ar, Buf *name, TldFn *tld_fn) {
FnTableEntry *fn_entry = tld_fn->fn_entry;
FnTypeId *fn_type_id = &fn_entry->type_entry->data.fn.fn_type_id;
const char *visib_mod_str = visib_mod_string(tld_fn->base.visib_mod);
const char *cc_str = calling_convention_string(fn_type_id->cc);
fprintf(ar->f, "%s%sfn %s(", visib_mod_str, cc_str, buf_ptr(&fn_entry->symbol_name));
for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
if (i != 0) {
fprintf(ar->f, ", ");
}
if (param_info->is_noalias) {
fprintf(ar->f, "noalias ");
}
Buf *param_name = tld_fn->fn_entry->param_names ? tld_fn->fn_entry->param_names[i] : buf_sprintf("arg%" ZIG_PRI_usize "", i);
fprintf(ar->f, "%s: %s", buf_ptr(param_name), buf_ptr(&param_info->type->name));
}
if (fn_type_id->return_type->id == TypeTableEntryIdVoid) {
fprintf(ar->f, ");\n");
} else {
fprintf(ar->f, ") -> %s;\n", buf_ptr(&fn_type_id->return_type->name));
}
}
static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) {
VariableTableEntry *var = tld_var->var;
const char *visib_mod_str = visib_mod_string(tld_var->base.visib_mod);
const char *const_or_var = const_or_var_string(var->src_is_const);
const char *extern_str = extern_string(var->linkage == VarLinkageExternal);
fprintf(ar->f, "%s%s%s %s", visib_mod_str, extern_str, const_or_var, buf_ptr(name));
if (var->value->type->id == TypeTableEntryIdNumLitFloat ||
var->value->type->id == TypeTableEntryIdNumLitInt ||
var->value->type->id == TypeTableEntryIdMetaType)
{
// skip type
} else {
fprintf(ar->f, ": %s", buf_ptr(&var->value->type->name));
}
if (var->value->special == ConstValSpecialRuntime) {
fprintf(ar->f, ";\n");
return;
}
fprintf(ar->f, " = ");
if (var->value->special == ConstValSpecialStatic &&
var->value->type->id == TypeTableEntryIdMetaType)
{
TypeTableEntry *type_entry = var->value->data.x_type;
if (type_entry->id == TypeTableEntryIdStruct) {
const char *layout_str = layout_string(type_entry->data.structure.layout);
fprintf(ar->f, "%sstruct {\n", layout_str);
if (type_entry->data.structure.complete) {
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *field = &type_entry->data.structure.fields[i];
fprintf(ar->f, " ");
print_symbol(ar, field->name);
fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name));
}
}
fprintf(ar->f, "}");
} else if (type_entry->id == TypeTableEntryIdEnum) {
const char *layout_str = layout_string(type_entry->data.enumeration.layout);
fprintf(ar->f, "%senum {\n", layout_str);
if (type_entry->data.enumeration.complete) {
for (size_t i = 0; i < type_entry->data.enumeration.src_field_count; i += 1) {
TypeEnumField *field = &type_entry->data.enumeration.fields[i];
fprintf(ar->f, " ");
print_symbol(ar, field->name);
if (field->type_entry->id == TypeTableEntryIdVoid) {
fprintf(ar->f, ",\n");
} else {
fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name));
}
}
}
fprintf(ar->f, "}");
} else if (type_entry->id == TypeTableEntryIdUnion) {
fprintf(ar->f, "union {");
fprintf(ar->f, "TODO");
fprintf(ar->f, "}");
} else if (type_entry->id == TypeTableEntryIdOpaque) {
if (buf_eql_buf(&type_entry->name, name)) {
fprintf(ar->f, "@OpaqueType()");
} else {
fprintf(ar->f, "%s", buf_ptr(&type_entry->name));
}
} else {
fprintf(ar->f, "%s", buf_ptr(&type_entry->name));
}
} else {
Buf buf = BUF_INIT;
buf_resize(&buf, 0);
render_const_value(ar->codegen, &buf, var->value);
fprintf(ar->f, "%s", buf_ptr(&buf));
}
fprintf(ar->f, ";\n");
}
void ast_render_decls(CodeGen *codegen, FILE *f, int indent_size, ImportTableEntry *import) {
AstRender ar = {0};
ar.codegen = codegen;
ar.f = f;
ar.indent_size = indent_size;
ar.indent = 0;
auto it = import->decls_scope->decl_table.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
Tld *tld = entry->value;
if (tld->name != nullptr && !buf_eql_buf(entry->key, tld->name)) {
fprintf(ar.f, "pub const ");
print_symbol(&ar, entry->key);
fprintf(ar.f, " = %s;\n", buf_ptr(tld->name));
continue;
}
switch (tld->id) {
case TldIdVar:
ast_render_tld_var(&ar, entry->key, (TldVar *)tld);
break;
case TldIdFn:
ast_render_tld_fn(&ar, entry->key, (TldFn *)tld);
break;
case TldIdContainer:
fprintf(stdout, "container\n");
break;
case TldIdCompTime:
fprintf(stdout, "comptime\n");
break;
}
}
}

View File

@ -19,7 +19,5 @@ void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
const char *container_string(ContainerKind kind);
void ast_render_decls(CodeGen *codegen, FILE *f, int indent_size, ImportTableEntry *import);
#endif

View File

@ -165,6 +165,25 @@ void bigint_init_signed(BigInt *dest, int64_t x) {
dest->data.digit = ((uint64_t)(-(x + 1))) + 1;
}
void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative) {
if (digit_count == 0) {
return bigint_init_unsigned(dest, 0);
} else if (digit_count == 1) {
dest->digit_count = 1;
dest->data.digit = digits[0];
dest->is_negative = is_negative;
bigint_normalize(dest);
return;
}
dest->digit_count = digit_count;
dest->is_negative = is_negative;
dest->data.digits = allocate_nonzero<uint64_t>(digit_count);
memcpy(dest->data.digits, digits, sizeof(uint64_t) * digit_count);
bigint_normalize(dest);
}
void bigint_init_bigint(BigInt *dest, const BigInt *src) {
if (src->digit_count == 0) {
return bigint_init_unsigned(dest, 0);

View File

@ -34,6 +34,7 @@ void bigint_init_u128(BigInt *dest, unsigned __int128 x);
void bigint_init_signed(BigInt *dest, int64_t x);
void bigint_init_bigint(BigInt *dest, const BigInt *src);
void bigint_init_bigfloat(BigInt *dest, const BigFloat *op);
void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative);
// panics if number won't fit
uint64_t bigint_as_unsigned(const BigInt *bigint);

View File

@ -469,7 +469,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
FnTableEntry *fn_table_entry = fn_scope->fn_entry;
if (!fn_table_entry->proto_node)
return get_di_scope(g, scope->parent);
unsigned line_number = (unsigned)fn_table_entry->proto_node->line + 1;
unsigned line_number = (unsigned)(fn_table_entry->proto_node->line == 0) ?
0 : (fn_table_entry->proto_node->line + 1);
unsigned scope_line = line_number;
bool is_definition = fn_table_entry->body_node != nullptr;
unsigned flags = 0;
@ -3328,6 +3329,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdTypeId:
case IrInstructionIdSetEvalBranchQuota:
case IrInstructionIdPtrTypeOf:
case IrInstructionIdOpaqueType:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@ -4732,6 +4734,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
}
static const char *bool_to_str(bool b) {

View File

@ -55,7 +55,6 @@ void codegen_add_assembly(CodeGen *g, Buf *path);
void codegen_add_object(CodeGen *g, Buf *object_path);
void codegen_parseh(CodeGen *g, Buf *path);
void codegen_render_ast(CodeGen *g, FILE *f, int indent_size);
#endif

View File

@ -79,11 +79,14 @@ ErrorMsg *err_msg_create_with_offset(Buf *path, size_t line, size_t column, size
for (;;) {
if (line_start_offset == 0) {
break;
} else if (source[line_start_offset] == '\n') {
}
line_start_offset -= 1;
if (source[line_start_offset] == '\n') {
line_start_offset += 1;
break;
}
line_start_offset -= 1;
}
size_t line_end_offset = offset;

View File

@ -559,6 +559,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) {
return IrInstructionIdAlignCast;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) {
return IrInstructionIdOpaqueType;
}
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@ -2238,6 +2242,12 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
return &instruction->base;
}
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
return nullptr;
}
@ -2956,6 +2966,10 @@ static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *i
}
}
static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType *instruction, size_t index) {
return nullptr;
}
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -3154,6 +3168,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_ptrtypeof_get_dep((IrInstructionPtrTypeOf *) instruction, index);
case IrInstructionIdAlignCast:
return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);
case IrInstructionIdOpaqueType:
return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
}
zig_unreachable();
}
@ -4578,6 +4594,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
}
case BuiltinFnIdOpaqueType:
return ir_build_opaque_type(irb, scope, node);
}
zig_unreachable();
}
@ -6044,27 +6062,30 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
return true;
}
static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {
if (exec->name) {
return exec->name;
} else {
FnTableEntry *fn_entry = exec_fn_entry(exec);
if (fn_entry) {
Buf *name = buf_alloc();
buf_append_buf(name, &fn_entry->symbol_name);
buf_appendf(name, "(");
render_instance_name_recursive(codegen, name, &fn_entry->fndef_scope->base, exec->begin_scope);
buf_appendf(name, ")");
return name;
} else {
return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);
}
}
}
static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
assert(node->type == NodeTypeContainerDecl);
ContainerKind kind = node->data.container_decl.kind;
Buf *name;
if (irb->exec->name) {
name = irb->exec->name;
} else {
FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
if (fn_entry) {
name = buf_alloc();
buf_append_buf(name, &fn_entry->symbol_name);
buf_appendf(name, "(");
render_instance_name_recursive(irb->codegen, name, &fn_entry->fndef_scope->base, irb->exec->begin_scope);
buf_appendf(name, ")");
} else {
name = buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", container_string(kind),
buf_ptr(node->owner->path), node->line + 1, node->column + 1);
}
}
Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node);
VisibMod visib_mod = VisibModPub;
TldContainer *tld_container = allocate<TldContainer>(1);
@ -6114,9 +6135,14 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
return irb->codegen->invalid_instruction;
}
IrInstruction *return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrInstruction *return_type;
if (node->data.fn_proto.return_type == nullptr) {
return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
} else {
return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
}
@ -13358,9 +13384,11 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc
if (ira->codegen->verbose) {
fprintf(stderr, "\nC imports:\n");
fprintf(stderr, "-----------\n");
ast_render_decls(ira->codegen, stderr, 4, child_import);
ast_render(ira->codegen, stderr, child_import->root, 4);
}
scan_decls(ira->codegen, child_import->decls_scope, child_import->root);
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_import = child_import;
return ira->codegen->builtin_types.entry_namespace;
@ -15136,6 +15164,14 @@ static TypeTableEntry *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstr
return result->value.type;
}
static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstructionOpaqueType *instruction) {
Buf *name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque", instruction->base.source_node);
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_type = get_opaque_type(ira->codegen, instruction->base.scope, instruction->base.source_node,
buf_ptr(name));
return ira->codegen->builtin_types.entry_type;
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -15322,6 +15358,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_ptr_type_of(ira, (IrInstructionPtrTypeOf *)instruction);
case IrInstructionIdAlignCast:
return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
case IrInstructionIdOpaqueType:
return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
}
zig_unreachable();
}
@ -15500,6 +15538,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdOffsetOf:
case IrInstructionIdTypeId:
case IrInstructionIdAlignCast:
case IrInstructionIdOpaqueType:
return false;
case IrInstructionIdAsm:
{
@ -15515,65 +15554,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {
}
zig_unreachable();
}
FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope) {
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdInternal);
buf_init_from_buf(&fn_entry->symbol_name, fn_name);
fn_entry->fndef_scope = create_fndef_scope(nullptr, parent_scope, fn_entry);
fn_entry->child_scope = &fn_entry->fndef_scope->base;
assert(var->value->type->id == TypeTableEntryIdMaybe);
TypeTableEntry *src_fn_type = var->value->type->data.maybe.child_type;
assert(src_fn_type->id == TypeTableEntryIdFn);
FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id;
new_fn_type.cc = CallingConventionUnspecified;
fn_entry->type_entry = get_fn_type(codegen, &new_fn_type);
IrBuilder ir_builder = {0};
IrBuilder *irb = &ir_builder;
irb->codegen = codegen;
irb->exec = &fn_entry->ir_executable;
AstNode *source_node = parent_scope->source_node;
size_t arg_count = fn_entry->type_entry->data.fn.fn_type_id.param_count;
IrInstruction **args = allocate<IrInstruction *>(arg_count);
VariableTableEntry **arg_vars = allocate<VariableTableEntry *>(arg_count);
define_local_param_variables(codegen, fn_entry, arg_vars);
Scope *scope = fn_entry->child_scope;
irb->current_basic_block = ir_build_basic_block(irb, scope, "Entry");
// Entry block gets a reference because we enter it to begin.
ir_ref_bb(irb->current_basic_block);
IrInstruction *maybe_fn_ptr = ir_build_var_ptr(irb, scope, source_node, var, true, false);
IrInstruction *unwrapped_fn_ptr = ir_build_unwrap_maybe(irb, scope, source_node, maybe_fn_ptr, true);
IrInstruction *fn_ref_instruction = ir_build_load_ptr(irb, scope, source_node, unwrapped_fn_ptr);
for (size_t i = 0; i < arg_count; i += 1) {
IrInstruction *var_ptr_instruction = ir_build_var_ptr(irb, scope, source_node, arg_vars[i], true, false);
args[i] = ir_build_load_ptr(irb, scope, source_node, var_ptr_instruction);
}
IrInstruction *call_instruction = ir_build_call(irb, scope, source_node, nullptr, fn_ref_instruction,
arg_count, args, false, false);
ir_build_return(irb, scope, source_node, call_instruction);
if (codegen->verbose) {
fprintf(stderr, "{\n");
ir_print(codegen, stderr, &fn_entry->ir_executable, 4);
fprintf(stderr, "}\n");
}
analyze_fn_ir(codegen, fn_entry, nullptr);
codegen->fn_defs.append(fn_entry);
return fn_entry;
}

View File

@ -24,6 +24,4 @@ TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutabl
bool ir_has_side_effects(IrInstruction *instruction);
ConstExprValue *const_ptr_pointee(CodeGen *codegen, ConstExprValue *const_val);
FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope);
#endif

View File

@ -944,6 +944,10 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio
fprintf(irp->f, ")");
}
static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
fprintf(irp->f, "@OpaqueType()");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -1240,6 +1244,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAlignCast:
ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction);
break;
case IrInstructionIdOpaqueType:
ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
break;
}
fprintf(irp->f, "\n");
}

View File

@ -670,7 +670,7 @@ int main(int argc, char **argv) {
return EXIT_SUCCESS;
} else if (cmd == CmdParseH) {
codegen_parseh(g, in_file_buf);
ast_render_decls(g, stdout, 4, g->root_import);
ast_render(g, stdout, g->root_import->root, 4);
if (timing_info)
codegen_print_timing_report(g, stdout);
return EXIT_SUCCESS;

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,8 @@ struct ParseContext {
ZigList<Token> *tokens;
ImportTableEntry *owner;
ErrColor err_color;
uint32_t *next_node_index;
// These buffers are used freqently so we preallocate them once here.
Buf *void_buf;
Buf *empty_buf;
};
__attribute__ ((format (printf, 4, 5)))
@ -70,8 +68,6 @@ static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
AstNode *node = allocate<AstNode>(1);
node->type = type;
node->owner = pc->owner;
node->create_index = *pc->next_node_index;
*pc->next_node_index += 1;
return node;
}
@ -279,7 +275,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
token = &pc->tokens->at(*token_index);
}
node->data.param_decl.name = pc->empty_buf;
node->data.param_decl.name = nullptr;
if (token->id == TokenIdSymbol) {
Token *next_token = &pc->tokens->at(*token_index + 1);
@ -2249,7 +2245,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
*token_index += 1;
node->data.fn_proto.name = token_buf(fn_name);
} else {
node->data.fn_proto.name = pc->empty_buf;
node->data.fn_proto.name = nullptr;
}
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
@ -2611,16 +2607,14 @@ static AstNode *ast_parse_root(ParseContext *pc, size_t *token_index) {
}
AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
ErrColor err_color, uint32_t *next_node_index)
ErrColor err_color)
{
ParseContext pc = {0};
pc.void_buf = buf_create_from_str("void");
pc.empty_buf = buf_create_from_str("");
pc.err_color = err_color;
pc.owner = owner;
pc.buf = buf;
pc.tokens = tokens;
pc.next_node_index = next_node_index;
size_t token_index = 0;
pc.root = ast_parse_root(&pc, &token_index);
return pc.root;

View File

@ -17,8 +17,7 @@ void ast_token_error(Token *token, const char *format, ...);
// This function is provided by generated code, generated by parsergen.cpp
AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color,
uint32_t *next_node_index);
AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
void ast_print(AstNode *node, int indent);

522
std/zlib/deflate.zig Normal file
View File

@ -0,0 +1,522 @@
const z_stream = struct {
/// next input byte */
next_in: &const u8,
/// number of bytes available at next_in
avail_in: u16,
/// total number of input bytes read so far
total_in: u32,
/// next output byte will go here
next_out: u8,
/// remaining free space at next_out
avail_out: u16,
/// total number of bytes output so far
total_out: u32,
/// last error message, NULL if no error
msg: ?&const u8,
/// not visible by applications
state:
struct internal_state FAR *state; // not visible by applications */
alloc_func zalloc; // used to allocate the internal state */
free_func zfree; // used to free the internal state */
voidpf opaque; // private data object passed to zalloc and zfree */
int data_type; // best guess about the data type: binary or text
// for deflate, or the decoding state for inflate */
uint32_t adler; // Adler-32 or CRC-32 value of the uncompressed data */
uint32_t reserved; // reserved for future use */
};
typedef struct internal_state {
z_stream * strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
uint8_t *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
uint8_t *pending_out; /* next pending byte to output to the stream */
ulg pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
gz_headerp gzhead; /* gzip header information to write */
ulg gzindex; /* where in extra, name, or comment */
uint8_t method; /* can only be DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
/* used by deflate.c: */
uint16_t w_size; /* LZ77 window size (32K by default) */
uint16_t w_bits; /* log2(w_size) (8..16) */
uint16_t w_mask; /* w_size - 1 */
uint8_t *window;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size. Also, it limits
* the window size to 64K, which is quite useful on MSDOS.
* To do: use the user input buffer as sliding window.
*/
ulg window_size;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
Posf *prev;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
Posf *head; /* Heads of the hash chains or NIL. */
uint16_t ins_h; /* hash index of string to be inserted */
uint16_t hash_size; /* number of elements in hash table */
uint16_t hash_bits; /* log2(hash_size) */
uint16_t hash_mask; /* hash_size-1 */
uint16_t hash_shift;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
long block_start;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
uint16_t match_length; /* length of best match */
IPos prev_match; /* previous match */
int match_available; /* set if previous match exists */
uint16_t strstart; /* start of string to insert */
uint16_t match_start; /* start of matching string */
uint16_t lookahead; /* number of valid bytes ahead in window */
uint16_t prev_length;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
uint16_t max_chain_length;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
uint16_t max_lazy_match;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
# define max_insert_length max_lazy_match
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
int level; /* compression level (1..9) */
int strategy; /* favor or force Huffman coding*/
uint16_t good_match;
/* Use a faster search when the previous match is longer than this */
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to suppress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
struct tree_desc_s l_desc; /* desc. for literal tree */
struct tree_desc_s d_desc; /* desc. for distance tree */
struct tree_desc_s bl_desc; /* desc. for bit length tree */
ush bl_count[MAX_BITS+1];
/* number of codes at each bit length for an optimal tree */
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
int heap_len; /* number of elements in the heap */
int heap_max; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
uch depth[2*L_CODES+1];
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
uchf *l_buf; /* buffer for literals or lengths */
uint16_t lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
uint16_t last_lit; /* running index in l_buf */
ushf *d_buf;
/* Buffer for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
uint16_t matches; /* number of string matches in current block */
uint16_t insert; /* bytes at end of window left to insert */
#ifdef ZLIB_DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
ush bi_buf;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
int bi_valid;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
ulg high_water;
/* High water mark offset in window for initialized bytes -- bytes above
* this are set to zero in order to avoid memory check warnings when
* longest match routines access bytes past the input. This is then
* updated to the new high water mark.
*/
} FAR deflate_state;
fn deflate(strm: &z_stream, flush: int) -> %void {
}
int deflate (z_stream * strm, int flush) {
int old_flush; /* value of flush param for previous deflate call */
deflate_state *s;
if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {
return Z_STREAM_ERROR;
}
s = strm->state;
if (strm->next_out == Z_NULL ||
(strm->avail_in != 0 && strm->next_in == Z_NULL) ||
(s->status == FINISH_STATE && flush != Z_FINISH)) {
ERR_RETURN(strm, Z_STREAM_ERROR);
}
if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
old_flush = s->last_flush;
s->last_flush = flush;
/* Flush as much pending output as possible */
if (s->pending != 0) {
flush_pending(strm);
if (strm->avail_out == 0) {
/* Since avail_out is 0, deflate will be called again with
* more output space, but possibly with both pending and
* avail_in equal to zero. There won't be anything to do,
* but this is not an error situation so make sure we
* return OK instead of BUF_ERROR at next call of deflate:
*/
s->last_flush = -1;
return Z_OK;
}
/* Make sure there is something to do and avoid duplicate consecutive
* flushes. For repeated and useless calls with Z_FINISH, we keep
* returning Z_STREAM_END instead of Z_BUF_ERROR.
*/
} else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
flush != Z_FINISH) {
ERR_RETURN(strm, Z_BUF_ERROR);
}
/* User must not provide more input after the first FINISH: */
if (s->status == FINISH_STATE && strm->avail_in != 0) {
ERR_RETURN(strm, Z_BUF_ERROR);
}
/* Write the header */
if (s->status == INIT_STATE) {
/* zlib header */
uint16_t header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
uint16_t level_flags;
if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
level_flags = 0;
else if (s->level < 6)
level_flags = 1;
else if (s->level == 6)
level_flags = 2;
else
level_flags = 3;
header |= (level_flags << 6);
if (s->strstart != 0) header |= PRESET_DICT;
header += 31 - (header % 31);
putShortMSB(s, header);
/* Save the adler32 of the preset dictionary: */
if (s->strstart != 0) {
putShortMSB(s, (uint16_t)(strm->adler >> 16));
putShortMSB(s, (uint16_t)(strm->adler & 0xffff));
}
strm->adler = adler32(0L, Z_NULL, 0);
s->status = BUSY_STATE;
/* Compression must start with an empty pending buffer */
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
}
#ifdef GZIP
if (s->status == GZIP_STATE) {
/* gzip header */
strm->adler = crc32(0L, Z_NULL, 0);
put_byte(s, 31);
put_byte(s, 139);
put_byte(s, 8);
if (s->gzhead == Z_NULL) {
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, s->level == 9 ? 2 :
(s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
4 : 0));
put_byte(s, OS_CODE);
s->status = BUSY_STATE;
/* Compression must start with an empty pending buffer */
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
}
else {
put_byte(s, (s->gzhead->text ? 1 : 0) +
(s->gzhead->hcrc ? 2 : 0) +
(s->gzhead->extra == Z_NULL ? 0 : 4) +
(s->gzhead->name == Z_NULL ? 0 : 8) +
(s->gzhead->comment == Z_NULL ? 0 : 16)
);
put_byte(s, (uint8_t)(s->gzhead->time & 0xff));
put_byte(s, (uint8_t)((s->gzhead->time >> 8) & 0xff));
put_byte(s, (uint8_t)((s->gzhead->time >> 16) & 0xff));
put_byte(s, (uint8_t)((s->gzhead->time >> 24) & 0xff));
put_byte(s, s->level == 9 ? 2 :
(s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
4 : 0));
put_byte(s, s->gzhead->os & 0xff);
if (s->gzhead->extra != Z_NULL) {
put_byte(s, s->gzhead->extra_len & 0xff);
put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
}
if (s->gzhead->hcrc)
strm->adler = crc32(strm->adler, s->pending_buf,
s->pending);
s->gzindex = 0;
s->status = EXTRA_STATE;
}
}
if (s->status == EXTRA_STATE) {
if (s->gzhead->extra != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */
uint16_t left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
while (s->pending + left > s->pending_buf_size) {
uint16_t copy = s->pending_buf_size - s->pending;
zmemcpy(s->pending_buf + s->pending,
s->gzhead->extra + s->gzindex, copy);
s->pending = s->pending_buf_size;
HCRC_UPDATE(beg);
s->gzindex += copy;
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
beg = 0;
left -= copy;
}
zmemcpy(s->pending_buf + s->pending,
s->gzhead->extra + s->gzindex, left);
s->pending += left;
HCRC_UPDATE(beg);
s->gzindex = 0;
}
s->status = NAME_STATE;
}
if (s->status == NAME_STATE) {
if (s->gzhead->name != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */
int val;
do {
if (s->pending == s->pending_buf_size) {
HCRC_UPDATE(beg);
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
beg = 0;
}
val = s->gzhead->name[s->gzindex++];
put_byte(s, val);
} while (val != 0);
HCRC_UPDATE(beg);
s->gzindex = 0;
}
s->status = COMMENT_STATE;
}
if (s->status == COMMENT_STATE) {
if (s->gzhead->comment != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */
int val;
do {
if (s->pending == s->pending_buf_size) {
HCRC_UPDATE(beg);
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
beg = 0;
}
val = s->gzhead->comment[s->gzindex++];
put_byte(s, val);
} while (val != 0);
HCRC_UPDATE(beg);
}
s->status = HCRC_STATE;
}
if (s->status == HCRC_STATE) {
if (s->gzhead->hcrc) {
if (s->pending + 2 > s->pending_buf_size) {
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
}
put_byte(s, (uint8_t)(strm->adler & 0xff));
put_byte(s, (uint8_t)((strm->adler >> 8) & 0xff));
strm->adler = crc32(0L, Z_NULL, 0);
}
s->status = BUSY_STATE;
/* Compression must start with an empty pending buffer */
flush_pending(strm);
if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
}
#endif
/* Start a new block or continue the current one.
*/
if (strm->avail_in != 0 || s->lookahead != 0 ||
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate;
bstate = s->level == 0 ? deflate_stored(s, flush) :
s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
s->strategy == Z_RLE ? deflate_rle(s, flush) :
(*(configuration_table[s->level].func))(s, flush);
if (bstate == finish_started || bstate == finish_done) {
s->status = FINISH_STATE;
}
if (bstate == need_more || bstate == finish_started) {
if (strm->avail_out == 0) {
s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
}
return Z_OK;
/* If flush != Z_NO_FLUSH && avail_out == 0, the next call
* of deflate should use the same flush parameter to make sure
* that the flush is complete. So we don't have to output an
* empty block here, this will be done at next call. This also
* ensures that for a very small output buffer, we emit at most
* one empty block.
*/
}
if (bstate == block_done) {
if (flush == Z_PARTIAL_FLUSH) {
_tr_align(s);
} else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
_tr_stored_block(s, (char*)0, 0L, 0);
/* For a full flush, this empty block will be recognized
* as a special marker by inflate_sync().
*/
if (flush == Z_FULL_FLUSH) {
CLEAR_HASH(s); /* forget history */
if (s->lookahead == 0) {
s->strstart = 0;
s->block_start = 0L;
s->insert = 0;
}
}
}
flush_pending(strm);
if (strm->avail_out == 0) {
s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
return Z_OK;
}
}
}
if (flush != Z_FINISH) return Z_OK;
if (s->wrap <= 0) return Z_STREAM_END;
/* Write the trailer */
#ifdef GZIP
if (s->wrap == 2) {
put_byte(s, (uint8_t)(strm->adler & 0xff));
put_byte(s, (uint8_t)((strm->adler >> 8) & 0xff));
put_byte(s, (uint8_t)((strm->adler >> 16) & 0xff));
put_byte(s, (uint8_t)((strm->adler >> 24) & 0xff));
put_byte(s, (uint8_t)(strm->total_in & 0xff));
put_byte(s, (uint8_t)((strm->total_in >> 8) & 0xff));
put_byte(s, (uint8_t)((strm->total_in >> 16) & 0xff));
put_byte(s, (uint8_t)((strm->total_in >> 24) & 0xff));
}
else
#endif
{
putShortMSB(s, (uint16_t)(strm->adler >> 16));
putShortMSB(s, (uint16_t)(strm->adler & 0xffff));
}
flush_pending(strm);
/* If avail_out is zero, the application will call deflate again
* to flush the rest.
*/
if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
return s->pending != 0 ? Z_OK : Z_STREAM_END;
}

969
std/zlib/inflate.zig Normal file
View File

@ -0,0 +1,969 @@
error Z_STREAM_ERROR;
error Z_STREAM_END;
error Z_NEED_DICT;
error Z_ERRNO;
error Z_STREAM_ERROR;
error Z_DATA_ERROR;
error Z_MEM_ERROR;
error Z_BUF_ERROR;
error Z_VERSION_ERROR;
pub Flush = enum {
NO_FLUSH,
PARTIAL_FLUSH,
SYNC_FLUSH,
FULL_FLUSH,
FINISH,
BLOCK,
TREES,
};
const code = struct {
/// operation, extra bits, table bits
op: u8,
/// bits in this part of the code
bits: u8,
/// offset in table or code value
val: u16,
};
/// State maintained between inflate() calls -- approximately 7K bytes, not
/// including the allocated sliding window, which is up to 32K bytes.
const inflate_state = struct {
z_stream * strm; /* pointer back to this zlib stream */
inflate_mode mode; /* current inflate mode */
int last; /* true if processing last block */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
bit 2 true to validate check value */
int havedict; /* true if dictionary provided */
int flags; /* gzip header method and flags (0 if zlib) */
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
unsigned long check; /* protected copy of check value */
unsigned long total; /* protected copy of output count */
gz_headerp head; /* where to save gzip header information */
/* sliding window */
unsigned wbits; /* log base 2 of requested window size */
unsigned wsize; /* window size or zero if not using window */
unsigned whave; /* valid bytes in the window */
unsigned wnext; /* window write index */
u8 FAR *window; /* allocated sliding window, if needed */
/* bit accumulator */
unsigned long hold; /* input bit accumulator */
unsigned bits; /* number of bits in "in" */
/* for string and stored block copying */
unsigned length; /* literal or length of data to copy */
unsigned offset; /* distance back to copy string from */
/* for table and code decoding */
unsigned extra; /* extra bits needed */
/* fixed and dynamic code tables */
code const FAR *lencode; /* starting table for length/literal codes */
code const FAR *distcode; /* starting table for distance codes */
unsigned lenbits; /* index bits for lencode */
unsigned distbits; /* index bits for distcode */
/* dynamic table building */
unsigned ncode; /* number of code length code lengths */
unsigned nlen; /* number of length code lengths */
unsigned ndist; /* number of distance code lengths */
unsigned have; /* number of code lengths in lens[] */
code FAR *next; /* next available space in codes[] */
unsigned short lens[320]; /* temporary storage for code lengths */
unsigned short work[288]; /* work area for code table building */
code codes[ENOUGH]; /* space for code tables */
int sane; /* if false, allow invalid distance too far */
int back; /* bits back of last unprocessed length/lit */
unsigned was; /* initial length of match */
};
const alloc_func = fn(opaque: &c_void, items: u16, size: u16);
const free_func = fn(opaque: &c_void, address: &c_void);
const z_stream = struct {
/// next input byte
next_in: &u8,
/// number of bytes available at next_in
avail_in: u16,
/// total number of input bytes read so far
total_in: u32,
/// next output byte will go here
next_out: &u8,
/// remaining free space at next_out
avail_out: u16,
/// total number of bytes output so far */
total_out: u32,
/// last error message, NULL if no error
msg: &const u8,
/// not visible by applications
state: &inflate_state,
/// used to allocate the internal state
zalloc: alloc_func,
/// used to free the internal state
zfree: free_func,
/// private data object passed to zalloc and zfree
opaque: &c_void,
/// best guess about the data type: binary or text
/// for deflate, or the decoding state for inflate
data_type: i32,
/// Adler-32 or CRC-32 value of the uncompressed data
adler: u32,
};
// Possible inflate modes between inflate() calls
/// i: waiting for magic header
pub const HEAD = 16180;
/// i: waiting for method and flags (gzip)
pub const FLAGS = 16181;
/// i: waiting for modification time (gzip)
pub const TIME = 16182;
/// i: waiting for extra flags and operating system (gzip)
pub const OS = 16183;
/// i: waiting for extra length (gzip)
pub const EXLEN = 16184;
/// i: waiting for extra bytes (gzip)
pub const EXTRA = 16185;
/// i: waiting for end of file name (gzip)
pub const NAME = 16186;
/// i: waiting for end of comment (gzip)
pub const COMMENT = 16187;
/// i: waiting for header crc (gzip)
pub const HCRC = 16188;
/// i: waiting for dictionary check value
pub const DICTID = 16189;
/// waiting for inflateSetDictionary() call
pub const DICT = 16190;
/// i: waiting for type bits, including last-flag bit
pub const TYPE = 16191;
/// i: same, but skip check to exit inflate on new block
pub const TYPEDO = 16192;
/// i: waiting for stored size (length and complement)
pub const STORED = 16193;
/// i/o: same as COPY below, but only first time in
pub const COPY_ = 16194;
/// i/o: waiting for input or output to copy stored block
pub const COPY = 16195;
/// i: waiting for dynamic block table lengths
pub const TABLE = 16196;
/// i: waiting for code length code lengths
pub const LENLENS = 16197;
/// i: waiting for length/lit and distance code lengths
pub const CODELENS = 16198;
/// i: same as LEN below, but only first time in
pub const LEN_ = 16199;
/// i: waiting for length/lit/eob code
pub const LEN = 16200;
/// i: waiting for length extra bits
pub const LENEXT = 16201;
/// i: waiting for distance code
pub const DIST = 16202;
/// i: waiting for distance extra bits
pub const DISTEXT = 16203;
/// o: waiting for output space to copy string
pub const MATCH = 16204;
/// o: waiting for output space to write literal
pub const LIT = 16205;
/// i: waiting for 32-bit check value
pub const CHECK = 16206;
/// i: waiting for 32-bit length (gzip)
pub const LENGTH = 16207;
/// finished check, done -- remain here until reset
pub const DONE = 16208;
/// got a data error -- remain here until reset
pub const BAD = 16209;
/// got an inflate() memory error -- remain here until reset
pub const MEM = 16210;
/// looking for synchronization bytes to restart inflate() */
pub const SYNC = 16211;
/// inflate() uses a state machine to process as much input data and generate as
/// much output data as possible before returning. The state machine is
/// structured roughly as follows:
///
/// for (;;) switch (state) {
/// ...
/// case STATEn:
/// if (not enough input data or output space to make progress)
/// return;
/// ... make progress ...
/// state = STATEm;
/// break;
/// ...
/// }
///
/// so when inflate() is called again, the same case is attempted again, and
/// if the appropriate resources are provided, the machine proceeds to the
/// next state. The NEEDBITS() macro is usually the way the state evaluates
/// whether it can proceed or should return. NEEDBITS() does the return if
/// the requested bits are not available. The typical use of the BITS macros
/// is:
///
/// NEEDBITS(n);
/// ... do something with BITS(n) ...
/// DROPBITS(n);
///
/// where NEEDBITS(n) either returns from inflate() if there isn't enough
/// input left to load n bits into the accumulator, or it continues. BITS(n)
/// gives the low n bits in the accumulator. When done, DROPBITS(n) drops
/// the low n bits off the accumulator. INITBITS() clears the accumulator
/// and sets the number of available bits to zero. BYTEBITS() discards just
/// enough bits to put the accumulator on a byte boundary. After BYTEBITS()
/// and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
///
/// NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
/// if there is no input available. The decoding of variable length codes uses
/// PULLBYTE() directly in order to pull just enough bytes to decode the next
/// code, and no more.
///
/// Some states loop until they get enough input, making sure that enough
/// state information is maintained to continue the loop where it left off
/// if NEEDBITS() returns in the loop. For example, want, need, and keep
/// would all have to actually be part of the saved state in case NEEDBITS()
/// returns:
///
/// case STATEw:
/// while (want < need) {
/// NEEDBITS(n);
/// keep[want++] = BITS(n);
/// DROPBITS(n);
/// }
/// state = STATEx;
/// case STATEx:
///
/// As shown above, if the next state is also the next case, then the break
/// is omitted.
///
/// A state may also return if there is not enough output space available to
/// complete that state. Those states are copying stored data, writing a
/// literal byte, and copying a matching string.
///
/// When returning, a "goto inf_leave" is used to update the total counters,
/// update the check value, and determine whether any progress has been made
/// during that inflate() call in order to return the proper return code.
/// Progress is defined as a change in either strm->avail_in or strm->avail_out.
/// When there is a window, goto inf_leave will update the window with the last
/// output written. If a goto inf_leave occurs in the middle of decompression
/// and there is no window currently, goto inf_leave will create one and copy
/// output to the window for the next call of inflate().
///
/// In this implementation, the flush parameter of inflate() only affects the
/// return code (per zlib.h). inflate() always writes as much as possible to
/// strm->next_out, given the space available and the provided input--the effect
/// documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
/// the allocation of and copying into a sliding window until necessary, which
/// provides the effect documented in zlib.h for Z_FINISH when the entire input
/// stream available. So the only thing the flush parameter actually does is:
/// when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
/// will return Z_BUF_ERROR if it has not reached the end of the stream.
pub fn inflate(strm: &z_stream, flush: Flush, gunzip: bool) -> %void {
// next input
var next: &const u8 = undefined;
// next output
var put: &u8 = undefined;
// available input and output
var have: u16 = undefined;
var left: u16 = undefined;
// bit buffer
var hold: u32 = undefined;
// bits in bit buffer
var bits: u16 = undefined;
// save starting available input and output
var in: u16 = undefined;
var out: u16 = undefined;
// number of stored or match bytes to copy
var copy: u16 = undefined;
// where to copy match bytes from
var from: &u8 = undefined;
// current decoding table entry
var here: code = undefined;
// parent table entry
var last: code = undefined;
// length to copy for repeats, bits to drop
var len: u16 = undefined;
// return code
var ret: error = undefined;
// buffer for gzip header crc calculation
var hbuf: [4]u8 = undefined;
// permutation of code lengths
const short_order = []u16 = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
if (inflateStateCheck(strm) or strm.next_out == Z_NULL or (strm.next_in == Z_NULL and strm.avail_in != 0)) {
return error.Z_STREAM_ERROR;
}
var state: &inflate_state = strm.state;
if (state.mode == TYPE) {
state.mode = TYPEDO; // skip check
}
put = strm.next_out; \
left = strm.avail_out; \
next = strm.next_in; \
have = strm.avail_in; \
hold = state.hold; \
bits = state.bits; \
in = have;
out = left;
ret = Z_OK;
for (;;)
switch (state.mode) {
case HEAD:
if (state.wrap == 0) {
state.mode = TYPEDO;
break;
}
NEEDBITS(16);
#ifdef GUNZIP
if ((state.wrap & 2) && hold == 0x8b1f) { /* gzip header */
if (state.wbits == 0)
state.wbits = 15;
state.check = crc32(0L, Z_NULL, 0);
CRC2(state.check, hold);
INITBITS();
state.mode = FLAGS;
break;
}
state.flags = 0; /* expect zlib header */
if (state.head != Z_NULL)
state.head.done = -1;
if (!(state.wrap & 1) || /* check if zlib header allowed */
#else
if (
#endif
((BITS(8) << 8) + (hold >> 8)) % 31) {
strm.msg = (char *)"incorrect header check";
state.mode = BAD;
break;
}
if (BITS(4) != Z_DEFLATED) {
strm.msg = (char *)"unknown compression method";
state.mode = BAD;
break;
}
DROPBITS(4);
len = BITS(4) + 8;
if (state.wbits == 0)
state.wbits = len;
if (len > 15 || len > state.wbits) {
strm.msg = (char *)"invalid window size";
state.mode = BAD;
break;
}
state.dmax = 1U << len;
Tracev((stderr, "inflate: zlib header ok\n"));
strm.adler = state.check = adler32(0L, Z_NULL, 0);
state.mode = hold & 0x200 ? DICTID : TYPE;
INITBITS();
break;
#ifdef GUNZIP
case FLAGS:
NEEDBITS(16);
state.flags = (int)(hold);
if ((state.flags & 0xff) != Z_DEFLATED) {
strm.msg = (char *)"unknown compression method";
state.mode = BAD;
break;
}
if (state.flags & 0xe000) {
strm.msg = (char *)"unknown header flags set";
state.mode = BAD;
break;
}
if (state.head != Z_NULL)
state.head.text = (int)((hold >> 8) & 1);
if ((state.flags & 0x0200) && (state.wrap & 4))
CRC2(state.check, hold);
INITBITS();
state.mode = TIME;
case TIME:
NEEDBITS(32);
if (state.head != Z_NULL)
state.head.time = hold;
if ((state.flags & 0x0200) && (state.wrap & 4))
CRC4(state.check, hold);
INITBITS();
state.mode = OS;
case OS:
NEEDBITS(16);
if (state.head != Z_NULL) {
state.head.xflags = (int)(hold & 0xff);
state.head.os = (int)(hold >> 8);
}
if ((state.flags & 0x0200) && (state.wrap & 4))
CRC2(state.check, hold);
INITBITS();
state.mode = EXLEN;
case EXLEN:
if (state.flags & 0x0400) {
NEEDBITS(16);
state.length = (unsigned)(hold);
if (state.head != Z_NULL)
state.head.extra_len = (unsigned)hold;
if ((state.flags & 0x0200) && (state.wrap & 4))
CRC2(state.check, hold);
INITBITS();
}
else if (state.head != Z_NULL)
state.head.extra = Z_NULL;
state.mode = EXTRA;
case EXTRA:
if (state.flags & 0x0400) {
copy = state.length;
if (copy > have) copy = have;
if (copy) {
if (state.head != Z_NULL &&
state.head.extra != Z_NULL) {
len = state.head.extra_len - state.length;
zmemcpy(state.head.extra + len, next,
len + copy > state.head.extra_max ?
state.head.extra_max - len : copy);
}
if ((state.flags & 0x0200) && (state.wrap & 4))
state.check = crc32(state.check, next, copy);
have -= copy;
next += copy;
state.length -= copy;
}
if (state.length) goto inf_leave;
}
state.length = 0;
state.mode = NAME;
case NAME:
if (state.flags & 0x0800) {
if (have == 0) goto inf_leave;
copy = 0;
do {
len = (unsigned)(next[copy++]);
if (state.head != Z_NULL &&
state.head.name != Z_NULL &&
state.length < state.head.name_max)
state.head.name[state.length++] = (Bytef)len;
} while (len && copy < have);
if ((state.flags & 0x0200) && (state.wrap & 4))
state.check = crc32(state.check, next, copy);
have -= copy;
next += copy;
if (len) goto inf_leave;
}
else if (state.head != Z_NULL)
state.head.name = Z_NULL;
state.length = 0;
state.mode = COMMENT;
case COMMENT:
if (state.flags & 0x1000) {
if (have == 0) goto inf_leave;
copy = 0;
do {
len = (unsigned)(next[copy++]);
if (state.head != Z_NULL &&
state.head.comment != Z_NULL &&
state.length < state.head.comm_max)
state.head.comment[state.length++] = (Bytef)len;
} while (len && copy < have);
if ((state.flags & 0x0200) && (state.wrap & 4))
state.check = crc32(state.check, next, copy);
have -= copy;
next += copy;
if (len) goto inf_leave;
}
else if (state.head != Z_NULL)
state.head.comment = Z_NULL;
state.mode = HCRC;
case HCRC:
if (state.flags & 0x0200) {
NEEDBITS(16);
if ((state.wrap & 4) && hold != (state.check & 0xffff)) {
strm.msg = (char *)"header crc mismatch";
state.mode = BAD;
break;
}
INITBITS();
}
if (state.head != Z_NULL) {
state.head.hcrc = (int)((state.flags >> 9) & 1);
state.head.done = 1;
}
strm.adler = state.check = crc32(0L, Z_NULL, 0);
state.mode = TYPE;
break;
#endif
case DICTID:
NEEDBITS(32);
strm.adler = state.check = ZSWAP32(hold);
INITBITS();
state.mode = DICT;
case DICT:
if (state.havedict == 0) {
strm.next_out = put; \
strm.avail_out = left; \
strm.next_in = next; \
strm.avail_in = have; \
state.hold = hold; \
state.bits = bits; \
return Z_NEED_DICT;
}
strm.adler = state.check = adler32(0L, Z_NULL, 0);
state.mode = TYPE;
case TYPE:
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
case TYPEDO:
if (state.last) {
BYTEBITS();
state.mode = CHECK;
break;
}
NEEDBITS(3);
state.last = BITS(1);
DROPBITS(1);
switch (BITS(2)) {
case 0: /* stored block */
Tracev((stderr, "inflate: stored block%s\n",
state.last ? " (last)" : ""));
state.mode = STORED;
break;
case 1: /* fixed block */
fixedtables(state);
Tracev((stderr, "inflate: fixed codes block%s\n",
state.last ? " (last)" : ""));
state.mode = LEN_; /* decode codes */
if (flush == Z_TREES) {
DROPBITS(2);
goto inf_leave;
}
break;
case 2: /* dynamic block */
Tracev((stderr, "inflate: dynamic codes block%s\n",
state.last ? " (last)" : ""));
state.mode = TABLE;
break;
case 3:
strm.msg = (char *)"invalid block type";
state.mode = BAD;
}
DROPBITS(2);
break;
case STORED:
BYTEBITS(); /* go to byte boundary */
NEEDBITS(32);
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
strm.msg = (char *)"invalid stored block lengths";
state.mode = BAD;
break;
}
state.length = (unsigned)hold & 0xffff;
Tracev((stderr, "inflate: stored length %u\n",
state.length));
INITBITS();
state.mode = COPY_;
if (flush == Z_TREES) goto inf_leave;
case COPY_:
state.mode = COPY;
case COPY:
copy = state.length;
if (copy) {
if (copy > have) copy = have;
if (copy > left) copy = left;
if (copy == 0) goto inf_leave;
zmemcpy(put, next, copy);
have -= copy;
next += copy;
left -= copy;
put += copy;
state.length -= copy;
break;
}
Tracev((stderr, "inflate: stored end\n"));
state.mode = TYPE;
break;
case TABLE:
NEEDBITS(14);
state.nlen = BITS(5) + 257;
DROPBITS(5);
state.ndist = BITS(5) + 1;
DROPBITS(5);
state.ncode = BITS(4) + 4;
DROPBITS(4);
#ifndef PKZIP_BUG_WORKAROUND
if (state.nlen > 286 || state.ndist > 30) {
strm.msg = (char *)"too many length or distance symbols";
state.mode = BAD;
break;
}
#endif
Tracev((stderr, "inflate: table sizes ok\n"));
state.have = 0;
state.mode = LENLENS;
case LENLENS:
while (state.have < state.ncode) {
NEEDBITS(3);
state.lens[order[state.have++]] = (unsigned short)BITS(3);
DROPBITS(3);
}
while (state.have < 19)
state.lens[order[state.have++]] = 0;
state.next = state.codes;
state.lencode = (const code FAR *)(state.next);
state.lenbits = 7;
ret = inflate_table(CODES, state.lens, 19, &(state.next),
&(state.lenbits), state.work);
if (ret) {
strm.msg = (char *)"invalid code lengths set";
state.mode = BAD;
break;
}
Tracev((stderr, "inflate: code lengths ok\n"));
state.have = 0;
state.mode = CODELENS;
case CODELENS:
while (state.have < state.nlen + state.ndist) {
for (;;) {
here = state.lencode[BITS(state.lenbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if (here.val < 16) {
DROPBITS(here.bits);
state.lens[state.have++] = here.val;
}
else {
if (here.val == 16) {
NEEDBITS(here.bits + 2);
DROPBITS(here.bits);
if (state.have == 0) {
strm.msg = (char *)"invalid bit length repeat";
state.mode = BAD;
break;
}
len = state.lens[state.have - 1];
copy = 3 + BITS(2);
DROPBITS(2);
}
else if (here.val == 17) {
NEEDBITS(here.bits + 3);
DROPBITS(here.bits);
len = 0;
copy = 3 + BITS(3);
DROPBITS(3);
}
else {
NEEDBITS(here.bits + 7);
DROPBITS(here.bits);
len = 0;
copy = 11 + BITS(7);
DROPBITS(7);
}
if (state.have + copy > state.nlen + state.ndist) {
strm.msg = (char *)"invalid bit length repeat";
state.mode = BAD;
break;
}
while (copy--)
state.lens[state.have++] = (unsigned short)len;
}
}
/* handle error breaks in while */
if (state.mode == BAD) break;
/* check for end-of-block code (better have one) */
if (state.lens[256] == 0) {
strm.msg = (char *)"invalid code -- missing end-of-block";
state.mode = BAD;
break;
}
/* build code tables -- note: do not change the lenbits or distbits
values here (9 and 6) without reading the comments in inftrees.h
concerning the ENOUGH constants, which depend on those values */
state.next = state.codes;
state.lencode = (const code FAR *)(state.next);
state.lenbits = 9;
ret = inflate_table(LENS, state.lens, state.nlen, &(state.next),
&(state.lenbits), state.work);
if (ret) {
strm.msg = (char *)"invalid literal/lengths set";
state.mode = BAD;
break;
}
state.distcode = (const code FAR *)(state.next);
state.distbits = 6;
ret = inflate_table(DISTS, state.lens + state.nlen, state.ndist,
&(state.next), &(state.distbits), state.work);
if (ret) {
strm.msg = (char *)"invalid distances set";
state.mode = BAD;
break;
}
Tracev((stderr, "inflate: codes ok\n"));
state.mode = LEN_;
if (flush == Z_TREES) goto inf_leave;
case LEN_:
state.mode = LEN;
case LEN:
if (have >= 6 && left >= 258) {
strm.next_out = put; \
strm.avail_out = left; \
strm.next_in = next; \
strm.avail_in = have; \
state.hold = hold; \
state.bits = bits; \
inflate_fast(strm, out);
put = strm.next_out; \
left = strm.avail_out; \
next = strm.next_in; \
have = strm.avail_in; \
hold = state.hold; \
bits = state.bits; \
if (state.mode == TYPE)
state.back = -1;
break;
}
state.back = 0;
for (;;) {
here = state.lencode[BITS(state.lenbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if (here.op && (here.op & 0xf0) == 0) {
last = here;
for (;;) {
here = state.lencode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if ((unsigned)(last.bits + here.bits) <= bits) break;
PULLBYTE();
}
DROPBITS(last.bits);
state.back += last.bits;
}
DROPBITS(here.bits);
state.back += here.bits;
state.length = (unsigned)here.val;
if ((int)(here.op) == 0) {
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here.val));
state.mode = LIT;
break;
}
if (here.op & 32) {
Tracevv((stderr, "inflate: end of block\n"));
state.back = -1;
state.mode = TYPE;
break;
}
if (here.op & 64) {
strm.msg = (char *)"invalid literal/length code";
state.mode = BAD;
break;
}
state.extra = (unsigned)(here.op) & 15;
state.mode = LENEXT;
case LENEXT:
if (state.extra) {
NEEDBITS(state.extra);
state.length += BITS(state.extra);
DROPBITS(state.extra);
state.back += state.extra;
}
Tracevv((stderr, "inflate: length %u\n", state.length));
state.was = state.length;
state.mode = DIST;
case DIST:
for (;;) {
here = state.distcode[BITS(state.distbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if ((here.op & 0xf0) == 0) {
last = here;
for (;;) {
here = state.distcode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if ((unsigned)(last.bits + here.bits) <= bits) break;
PULLBYTE();
}
DROPBITS(last.bits);
state.back += last.bits;
}
DROPBITS(here.bits);
state.back += here.bits;
if (here.op & 64) {
strm.msg = (char *)"invalid distance code";
state.mode = BAD;
break;
}
state.offset = (unsigned)here.val;
state.extra = (unsigned)(here.op) & 15;
state.mode = DISTEXT;
case DISTEXT:
if (state.extra) {
NEEDBITS(state.extra);
state.offset += BITS(state.extra);
DROPBITS(state.extra);
state.back += state.extra;
}
#ifdef INFLATE_STRICT
if (state.offset > state.dmax) {
strm.msg = (char *)"invalid distance too far back";
state.mode = BAD;
break;
}
#endif
Tracevv((stderr, "inflate: distance %u\n", state.offset));
state.mode = MATCH;
case MATCH:
if (left == 0) goto inf_leave;
copy = out - left;
if (state.offset > copy) { /* copy from window */
copy = state.offset - copy;
if (copy > state.whave) {
if (state.sane) {
strm.msg = (char *)"invalid distance too far back";
state.mode = BAD;
break;
}
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
Trace((stderr, "inflate.c too far\n"));
copy -= state.whave;
if (copy > state.length) copy = state.length;
if (copy > left) copy = left;
left -= copy;
state.length -= copy;
do {
*put++ = 0;
} while (--copy);
if (state.length == 0) state.mode = LEN;
break;
#endif
}
if (copy > state.wnext) {
copy -= state.wnext;
from = state.window + (state.wsize - copy);
}
else
from = state.window + (state.wnext - copy);
if (copy > state.length) copy = state.length;
}
else { /* copy from output */
from = put - state.offset;
copy = state.length;
}
if (copy > left) copy = left;
left -= copy;
state.length -= copy;
do {
*put++ = *from++;
} while (--copy);
if (state.length == 0) state.mode = LEN;
break;
case LIT:
if (left == 0) goto inf_leave;
*put++ = (u8)(state.length);
left--;
state.mode = LEN;
break;
case CHECK:
if (state.wrap) {
NEEDBITS(32);
out -= left;
strm.total_out += out;
state.total += out;
if ((state.wrap & 4) && out)
strm.adler = state.check =
UPDATE(state.check, put - out, out);
out = left;
if ((state.wrap & 4) && (
#ifdef GUNZIP
state.flags ? hold :
#endif
ZSWAP32(hold)) != state.check) {
strm.msg = (char *)"incorrect data check";
state.mode = BAD;
break;
}
INITBITS();
Tracev((stderr, "inflate: check matches trailer\n"));
}
#ifdef GUNZIP
state.mode = LENGTH;
case LENGTH:
if (state.wrap && state.flags) {
NEEDBITS(32);
if (hold != (state.total & 0xffffffffUL)) {
strm.msg = (char *)"incorrect length check";
state.mode = BAD;
break;
}
INITBITS();
Tracev((stderr, "inflate: length matches trailer\n"));
}
#endif
state.mode = DONE;
case DONE:
ret = Z_STREAM_END;
goto inf_leave;
case BAD:
ret = Z_DATA_ERROR;
goto inf_leave;
case MEM:
return Z_MEM_ERROR;
case SYNC:
default:
return Z_STREAM_ERROR;
}
/*
Return from inflate(), updating the total counts and the check value.
If there was no progress during the inflate() call, return a buffer
error. Call updatewindow() to create and/or update the window state.
Note: a memory error from inflate() is non-recoverable.
*/
inf_leave:
strm.next_out = put; \
strm.avail_out = left; \
strm.next_in = next; \
strm.avail_in = have; \
state.hold = hold; \
state.bits = bits; \
if (state.wsize || (out != strm.avail_out && state.mode < BAD &&
(state.mode < CHECK || flush != Z_FINISH)))
if (updatewindow(strm, strm.next_out, out - strm.avail_out)) {
state.mode = MEM;
return Z_MEM_ERROR;
}
in -= strm.avail_in;
out -= strm.avail_out;
strm.total_in += in;
strm.total_out += out;
state.total += out;
if ((state.wrap & 4) && out)
strm.adler = state.check =
UPDATE(state.check, strm.next_out - out, out);
strm.data_type = (int)state.bits + (state.last ? 64 : 0) +
(state.mode == TYPE ? 128 : 0) +
(state.mode == LEN_ || state.mode == COPY_ ? 256 : 0);
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
ret = Z_BUF_ERROR;
return ret;
}
local int inflateStateCheck(z_stream * strm) {
struct inflate_state FAR *state;
if (strm == Z_NULL ||
strm.zalloc == (alloc_func)0 || strm.zfree == (free_func)0)
return 1;
state = (struct inflate_state FAR *)strm.state;
if (state == Z_NULL || state.strm != strm ||
state.mode < HEAD || state.mode > SYNC)
return 1;
return 0;
}

View File

@ -538,3 +538,11 @@ export fn writeToVRam() {
test "pointer child field" {
assert((&u32).child == u32);
}
const OpaqueA = @OpaqueType();
const OpaqueB = @OpaqueType();
test "@OpaqueType" {
assert(&OpaqueA != &OpaqueB);
assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
}

View File

@ -2079,4 +2079,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack",
".tmp_source.zig:2:8: note: called from here",
".tmp_source.zig:1:10: note: called from here");
cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()",
\\const Derp = @OpaqueType();
\\extern fn bar(d: &Derp);
\\export fn foo() {
\\ const x = u8(1);
\\ bar(@ptrCast(&c_void, &x));
\\}
,
".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'");
}

View File

@ -21,6 +21,16 @@ pub fn addCases(cases: &tests.ParseHContext) {
\\pub extern fn foo() -> noreturn;
);
cases.add("simple function",
\\int abs(int a) {
\\ return a < 0 ? -a : a;
\\}
,
\\export fn abs(a: c_int) -> c_int {
\\ return if (a < 0) -a else a;
\\}
);
cases.add("enums",
\\enum Foo {
\\ FooA,
@ -34,13 +44,13 @@ pub fn addCases(cases: &tests.ParseHContext) {
\\ @"1",
\\};
,
\\pub const FooA = 0;
\\pub const FooA = enum_Foo.A;
,
\\pub const FooB = 1;
\\pub const FooB = enum_Foo.B;
,
\\pub const Foo1 = 2;
\\pub const Foo1 = enum_Foo.@"1";
,
\\pub const Foo = enum_Foo
\\pub const Foo = enum_Foo;
);
cases.add("restrict -> noalias",
@ -84,9 +94,9 @@ pub fn addCases(cases: &tests.ParseHContext) {
\\ B,
\\};
,
\\pub const BarA = 0;
\\pub const BarA = enum_Bar.A;
,
\\pub const BarB = 1;
\\pub const BarB = enum_Bar.B;
,
\\pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);
,
@ -180,7 +190,7 @@ pub fn addCases(cases: &tests.ParseHContext) {
,
\\pub const Foo = c_void;
,
\\pub extern fn fun(a: ?&c_void);
\\pub extern fn fun(a: ?&Foo) -> Foo;
);
cases.add("generate inline func for #define global extern fn",
@ -192,17 +202,21 @@ pub fn addCases(cases: &tests.ParseHContext) {
,
\\pub extern var fn_ptr: ?extern fn();
,
\\pub fn foo();
\\pub inline fn foo() {
\\ ??fn_ptr()
\\}
,
\\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
,
\\pub fn bar(arg0: c_int, arg1: f32) -> u8;
\\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 {
\\ ??fn_ptr2(arg0, arg1)
\\}
);
cases.add("#define string",
\\#define foo "a string"
,
\\pub const foo: &const u8 = &(c str lit);
\\pub const foo = c"a string";
);
cases.add("__cdecl doesn't mess up function pointers",
@ -220,43 +234,43 @@ pub fn addCases(cases: &tests.ParseHContext) {
cases.add("u integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_uint = 32;
\\pub const SDL_INIT_VIDEO = c_uint(32);
);
cases.add("l integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_long = 32;
\\pub const SDL_INIT_VIDEO = c_long(32);
);
cases.add("ul integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_ulong = 32;
\\pub const SDL_INIT_VIDEO = c_ulong(32);
);
cases.add("lu integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_ulong = 32;
\\pub const SDL_INIT_VIDEO = c_ulong(32);
);
cases.add("ll integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_longlong = 32;
\\pub const SDL_INIT_VIDEO = c_longlong(32);
);
cases.add("ull integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_ulonglong = 32;
\\pub const SDL_INIT_VIDEO = c_ulonglong(32);
);
cases.add("llu integer suffix after hex literal",
\\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
,
\\pub const SDL_INIT_VIDEO: c_ulonglong = 32;
\\pub const SDL_INIT_VIDEO = c_ulonglong(32);
);
cases.add("zig keywords in C code",
@ -276,9 +290,9 @@ pub fn addCases(cases: &tests.ParseHContext) {
\\#define FOO2 "aoeu\0234 derp"
\\#define FOO_CHAR '\077'
,
\\pub const FOO: &const u8 = &(c str lit);
\\pub const FOO = c"aoeu\x13 derp";
,
\\pub const FOO2: &const u8 = &(c str lit);
\\pub const FOO2 = c"aoeu\x134 derp";
,
\\pub const FOO_CHAR = 63;
);