Commit ee9d1d0414

Andrew Kelley <superjoe30@gmail.com>
2017-09-01 09:16:35
c-to-zig: return statement
1 parent 8485041
src/all_types.hpp
@@ -833,7 +833,6 @@ struct AstNode {
     enum NodeType type;
     size_t line;
     size_t column;
-    uint32_t create_index; // for determinism purposes
     ImportTableEntry *owner;
     union {
         AstNodeRoot root;
@@ -1523,7 +1522,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;
src/analyze.cpp
@@ -3163,8 +3163,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);
src/parseh.cpp
@@ -17,6 +17,7 @@
 
 #include <clang/Frontend/ASTUnit.h>
 #include <clang/Frontend/CompilerInstance.h>
+#include <clang/AST/Expr.h>
 
 #include <string.h>
 
@@ -54,6 +55,7 @@ struct Context {
     uint32_t next_anon_index;
 
     CodeGen *codegen;
+    ASTContext *ctx;
 };
 
 static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl,
@@ -602,9 +604,477 @@ static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *de
     return resolve_qual_type_with_table(c, qt, decl, &c->global_type_table);
 }
 
+#include "ast_render.hpp"
+
+static AstNode * ast_trans_stmt(Context *c, Stmt *stmt);
+
+static AstNode * ast_trans_expr(Context *c, Expr *expr) {
+    return ast_trans_stmt(c, expr);
+}
+
+static AstNode * ast_create_node(Context *c, const SourceRange &range, NodeType id) {
+    AstNode *node = allocate<AstNode>(1);
+    node->type = id;
+    node->owner = c->import;
+    // TODO line/column. mapping to C file??
+    return node;
+}
+
+static AstNode * ast_trans_compound_stmt(Context *c, CompoundStmt *stmt) {
+    AstNode *block_node = ast_create_node(c, stmt->getSourceRange(), NodeTypeBlock);
+    for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
+        AstNode *child_node = ast_trans_stmt(c, *it);
+        block_node->data.block.statements.append(child_node);
+    }
+    return block_node;
+}
+
+static AstNode *ast_trans_return_stmt(Context *c, ReturnStmt *stmt) {
+    Expr *value_expr = stmt->getRetValue();
+    if (value_expr == nullptr) {
+        zig_panic("TODO handle C return void");
+    } else {
+        AstNode *return_node = ast_create_node(c, stmt->getSourceRange(), NodeTypeReturnExpr);
+        return_node->data.return_expr.expr = ast_trans_expr(c, value_expr);
+        return return_node;
+    }
+}
+
+static void aps_int_to_bigint(Context *c, const llvm::APSInt &aps_int, BigInt *bigint) {
+    // TODO respect actually big integers
+    if (aps_int.isSigned()) {
+        if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
+            zig_panic("TODO actually bigint in C");
+        } else {
+            bigint_init_signed(bigint, aps_int.getExtValue());
+        }
+    } else {
+        if (aps_int > INT64_MAX) {
+            zig_panic("TODO actually bigint in C");
+        } else {
+            bigint_init_unsigned(bigint, aps_int.getExtValue());
+        }
+    }
+}
+static AstNode * ast_trans_integer_literal(Context *c, IntegerLiteral *stmt) {
+    AstNode *node = ast_create_node(c, stmt->getSourceRange(), NodeTypeIntLiteral);
+    llvm::APSInt result;
+    if (!stmt->EvaluateAsInt(result, *c->ctx)) {
+        fprintf(stderr, "TODO unable to convert integer literal to zig\n");
+    }
+    node->data.int_literal.bigint = allocate<BigInt>(1);
+    aps_int_to_bigint(c, result, node->data.int_literal.bigint);
+    return node;
+}
+
+static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) {
+    Stmt::StmtClass sc = stmt->getStmtClass();
+    switch (sc) {
+        case Stmt::ReturnStmtClass:
+            return ast_trans_return_stmt(c, (ReturnStmt *)stmt);
+        case Stmt::CompoundStmtClass:
+            return ast_trans_compound_stmt(c, (CompoundStmt *)stmt);
+        case Stmt::IntegerLiteralClass:
+            return ast_trans_integer_literal(c, (IntegerLiteral *)stmt);
+        case Stmt::CaseStmtClass:
+            zig_panic("TODO handle C CaseStmtClass");
+        case Stmt::DefaultStmtClass:
+            zig_panic("TODO handle C DefaultStmtClass");
+        case Stmt::SwitchStmtClass:
+            zig_panic("TODO handle C SwitchStmtClass");
+        case Stmt::WhileStmtClass:
+            zig_panic("TODO handle C WhileStmtClass");
+        case Stmt::NoStmtClass:
+            zig_panic("TODO handle C NoStmtClass");
+        case Stmt::GCCAsmStmtClass:
+            zig_panic("TODO handle C GCCAsmStmtClass");
+        case Stmt::MSAsmStmtClass:
+            zig_panic("TODO handle C MSAsmStmtClass");
+        case Stmt::AttributedStmtClass:
+            zig_panic("TODO handle C AttributedStmtClass");
+        case Stmt::BreakStmtClass:
+            zig_panic("TODO handle C BreakStmtClass");
+        case Stmt::CXXCatchStmtClass:
+            zig_panic("TODO handle C CXXCatchStmtClass");
+        case Stmt::CXXForRangeStmtClass:
+            zig_panic("TODO handle C CXXForRangeStmtClass");
+        case Stmt::CXXTryStmtClass:
+            zig_panic("TODO handle C CXXTryStmtClass");
+        case Stmt::CapturedStmtClass:
+            zig_panic("TODO handle C CapturedStmtClass");
+        case Stmt::ContinueStmtClass:
+            zig_panic("TODO handle C ContinueStmtClass");
+        case Stmt::CoreturnStmtClass:
+            zig_panic("TODO handle C CoreturnStmtClass");
+        case Stmt::CoroutineBodyStmtClass:
+            zig_panic("TODO handle C CoroutineBodyStmtClass");
+        case Stmt::DeclStmtClass:
+            zig_panic("TODO handle C DeclStmtClass");
+        case Stmt::DoStmtClass:
+            zig_panic("TODO handle C DoStmtClass");
+        case Stmt::BinaryConditionalOperatorClass:
+            zig_panic("TODO handle C BinaryConditionalOperatorClass");
+        case Stmt::ConditionalOperatorClass:
+            zig_panic("TODO handle C ConditionalOperatorClass");
+        case Stmt::AddrLabelExprClass:
+            zig_panic("TODO handle C AddrLabelExprClass");
+        case Stmt::ArrayInitIndexExprClass:
+            zig_panic("TODO handle C ArrayInitIndexExprClass");
+        case Stmt::ArrayInitLoopExprClass:
+            zig_panic("TODO handle C ArrayInitLoopExprClass");
+        case Stmt::ArraySubscriptExprClass:
+            zig_panic("TODO handle C ArraySubscriptExprClass");
+        case Stmt::ArrayTypeTraitExprClass:
+            zig_panic("TODO handle C ArrayTypeTraitExprClass");
+        case Stmt::AsTypeExprClass:
+            zig_panic("TODO handle C AsTypeExprClass");
+        case Stmt::AtomicExprClass:
+            zig_panic("TODO handle C AtomicExprClass");
+        case Stmt::BinaryOperatorClass:
+            zig_panic("TODO handle C BinaryOperatorClass");
+        case Stmt::CompoundAssignOperatorClass:
+            zig_panic("TODO handle C CompoundAssignOperatorClass");
+        case Stmt::BlockExprClass:
+            zig_panic("TODO handle C BlockExprClass");
+        case Stmt::CXXBindTemporaryExprClass:
+            zig_panic("TODO handle C CXXBindTemporaryExprClass");
+        case Stmt::CXXBoolLiteralExprClass:
+            zig_panic("TODO handle C CXXBoolLiteralExprClass");
+        case Stmt::CXXConstructExprClass:
+            zig_panic("TODO handle C CXXConstructExprClass");
+        case Stmt::CXXTemporaryObjectExprClass:
+            zig_panic("TODO handle C CXXTemporaryObjectExprClass");
+        case Stmt::CXXDefaultArgExprClass:
+            zig_panic("TODO handle C CXXDefaultArgExprClass");
+        case Stmt::CXXDefaultInitExprClass:
+            zig_panic("TODO handle C CXXDefaultInitExprClass");
+        case Stmt::CXXDeleteExprClass:
+            zig_panic("TODO handle C CXXDeleteExprClass");
+        case Stmt::CXXDependentScopeMemberExprClass:
+            zig_panic("TODO handle C CXXDependentScopeMemberExprClass");
+        case Stmt::CXXFoldExprClass:
+            zig_panic("TODO handle C CXXFoldExprClass");
+        case Stmt::CXXInheritedCtorInitExprClass:
+            zig_panic("TODO handle C CXXInheritedCtorInitExprClass");
+        case Stmt::CXXNewExprClass:
+            zig_panic("TODO handle C CXXNewExprClass");
+        case Stmt::CXXNoexceptExprClass:
+            zig_panic("TODO handle C CXXNoexceptExprClass");
+        case Stmt::CXXNullPtrLiteralExprClass:
+            zig_panic("TODO handle C CXXNullPtrLiteralExprClass");
+        case Stmt::CXXPseudoDestructorExprClass:
+            zig_panic("TODO handle C CXXPseudoDestructorExprClass");
+        case Stmt::CXXScalarValueInitExprClass:
+            zig_panic("TODO handle C CXXScalarValueInitExprClass");
+        case Stmt::CXXStdInitializerListExprClass:
+            zig_panic("TODO handle C CXXStdInitializerListExprClass");
+        case Stmt::CXXThisExprClass:
+            zig_panic("TODO handle C CXXThisExprClass");
+        case Stmt::CXXThrowExprClass:
+            zig_panic("TODO handle C CXXThrowExprClass");
+        case Stmt::CXXTypeidExprClass:
+            zig_panic("TODO handle C CXXTypeidExprClass");
+        case Stmt::CXXUnresolvedConstructExprClass:
+            zig_panic("TODO handle C CXXUnresolvedConstructExprClass");
+        case Stmt::CXXUuidofExprClass:
+            zig_panic("TODO handle C CXXUuidofExprClass");
+        case Stmt::CallExprClass:
+            zig_panic("TODO handle C CallExprClass");
+        case Stmt::CUDAKernelCallExprClass:
+            zig_panic("TODO handle C CUDAKernelCallExprClass");
+        case Stmt::CXXMemberCallExprClass:
+            zig_panic("TODO handle C CXXMemberCallExprClass");
+        case Stmt::CXXOperatorCallExprClass:
+            zig_panic("TODO handle C CXXOperatorCallExprClass");
+        case Stmt::UserDefinedLiteralClass:
+            zig_panic("TODO handle C UserDefinedLiteralClass");
+        case Stmt::CStyleCastExprClass:
+            zig_panic("TODO handle C CStyleCastExprClass");
+        case Stmt::CXXFunctionalCastExprClass:
+            zig_panic("TODO handle C CXXFunctionalCastExprClass");
+        case Stmt::CXXConstCastExprClass:
+            zig_panic("TODO handle C CXXConstCastExprClass");
+        case Stmt::CXXDynamicCastExprClass:
+            zig_panic("TODO handle C CXXDynamicCastExprClass");
+        case Stmt::CXXReinterpretCastExprClass:
+            zig_panic("TODO handle C CXXReinterpretCastExprClass");
+        case Stmt::CXXStaticCastExprClass:
+            zig_panic("TODO handle C CXXStaticCastExprClass");
+        case Stmt::ObjCBridgedCastExprClass:
+            zig_panic("TODO handle C ObjCBridgedCastExprClass");
+        case Stmt::ImplicitCastExprClass:
+            zig_panic("TODO handle C ImplicitCastExprClass");
+        case Stmt::CharacterLiteralClass:
+            zig_panic("TODO handle C CharacterLiteralClass");
+        case Stmt::ChooseExprClass:
+            zig_panic("TODO handle C ChooseExprClass");
+        case Stmt::CompoundLiteralExprClass:
+            zig_panic("TODO handle C CompoundLiteralExprClass");
+        case Stmt::ConvertVectorExprClass:
+            zig_panic("TODO handle C ConvertVectorExprClass");
+        case Stmt::CoawaitExprClass:
+            zig_panic("TODO handle C CoawaitExprClass");
+        case Stmt::CoyieldExprClass:
+            zig_panic("TODO handle C CoyieldExprClass");
+        case Stmt::DeclRefExprClass:
+            zig_panic("TODO handle C DeclRefExprClass");
+        case Stmt::DependentCoawaitExprClass:
+            zig_panic("TODO handle C DependentCoawaitExprClass");
+        case Stmt::DependentScopeDeclRefExprClass:
+            zig_panic("TODO handle C DependentScopeDeclRefExprClass");
+        case Stmt::DesignatedInitExprClass:
+            zig_panic("TODO handle C DesignatedInitExprClass");
+        case Stmt::DesignatedInitUpdateExprClass:
+            zig_panic("TODO handle C DesignatedInitUpdateExprClass");
+        case Stmt::ExprWithCleanupsClass:
+            zig_panic("TODO handle C ExprWithCleanupsClass");
+        case Stmt::ExpressionTraitExprClass:
+            zig_panic("TODO handle C ExpressionTraitExprClass");
+        case Stmt::ExtVectorElementExprClass:
+            zig_panic("TODO handle C ExtVectorElementExprClass");
+        case Stmt::FloatingLiteralClass:
+            zig_panic("TODO handle C FloatingLiteralClass");
+        case Stmt::FunctionParmPackExprClass:
+            zig_panic("TODO handle C FunctionParmPackExprClass");
+        case Stmt::GNUNullExprClass:
+            zig_panic("TODO handle C GNUNullExprClass");
+        case Stmt::GenericSelectionExprClass:
+            zig_panic("TODO handle C GenericSelectionExprClass");
+        case Stmt::ImaginaryLiteralClass:
+            zig_panic("TODO handle C ImaginaryLiteralClass");
+        case Stmt::ImplicitValueInitExprClass:
+            zig_panic("TODO handle C ImplicitValueInitExprClass");
+        case Stmt::InitListExprClass:
+            zig_panic("TODO handle C InitListExprClass");
+        case Stmt::LambdaExprClass:
+            zig_panic("TODO handle C LambdaExprClass");
+        case Stmt::MSPropertyRefExprClass:
+            zig_panic("TODO handle C MSPropertyRefExprClass");
+        case Stmt::MSPropertySubscriptExprClass:
+            zig_panic("TODO handle C MSPropertySubscriptExprClass");
+        case Stmt::MaterializeTemporaryExprClass:
+            zig_panic("TODO handle C MaterializeTemporaryExprClass");
+        case Stmt::MemberExprClass:
+            zig_panic("TODO handle C MemberExprClass");
+        case Stmt::NoInitExprClass:
+            zig_panic("TODO handle C NoInitExprClass");
+        case Stmt::OMPArraySectionExprClass:
+            zig_panic("TODO handle C OMPArraySectionExprClass");
+        case Stmt::ObjCArrayLiteralClass:
+            zig_panic("TODO handle C ObjCArrayLiteralClass");
+        case Stmt::ObjCAvailabilityCheckExprClass:
+            zig_panic("TODO handle C ObjCAvailabilityCheckExprClass");
+        case Stmt::ObjCBoolLiteralExprClass:
+            zig_panic("TODO handle C ObjCBoolLiteralExprClass");
+        case Stmt::ObjCBoxedExprClass:
+            zig_panic("TODO handle C ObjCBoxedExprClass");
+        case Stmt::ObjCDictionaryLiteralClass:
+            zig_panic("TODO handle C ObjCDictionaryLiteralClass");
+        case Stmt::ObjCEncodeExprClass:
+            zig_panic("TODO handle C ObjCEncodeExprClass");
+        case Stmt::ObjCIndirectCopyRestoreExprClass:
+            zig_panic("TODO handle C ObjCIndirectCopyRestoreExprClass");
+        case Stmt::ObjCIsaExprClass:
+            zig_panic("TODO handle C ObjCIsaExprClass");
+        case Stmt::ObjCIvarRefExprClass:
+            zig_panic("TODO handle C ObjCIvarRefExprClass");
+        case Stmt::ObjCMessageExprClass:
+            zig_panic("TODO handle C ObjCMessageExprClass");
+        case Stmt::ObjCPropertyRefExprClass:
+            zig_panic("TODO handle C ObjCPropertyRefExprClass");
+        case Stmt::ObjCProtocolExprClass:
+            zig_panic("TODO handle C ObjCProtocolExprClass");
+        case Stmt::ObjCSelectorExprClass:
+            zig_panic("TODO handle C ObjCSelectorExprClass");
+        case Stmt::ObjCStringLiteralClass:
+            zig_panic("TODO handle C ObjCStringLiteralClass");
+        case Stmt::ObjCSubscriptRefExprClass:
+            zig_panic("TODO handle C ObjCSubscriptRefExprClass");
+        case Stmt::OffsetOfExprClass:
+            zig_panic("TODO handle C OffsetOfExprClass");
+        case Stmt::OpaqueValueExprClass:
+            zig_panic("TODO handle C OpaqueValueExprClass");
+        case Stmt::UnresolvedLookupExprClass:
+            zig_panic("TODO handle C UnresolvedLookupExprClass");
+        case Stmt::UnresolvedMemberExprClass:
+            zig_panic("TODO handle C UnresolvedMemberExprClass");
+        case Stmt::PackExpansionExprClass:
+            zig_panic("TODO handle C PackExpansionExprClass");
+        case Stmt::ParenExprClass:
+            zig_panic("TODO handle C ParenExprClass");
+        case Stmt::ParenListExprClass:
+            zig_panic("TODO handle C ParenListExprClass");
+        case Stmt::PredefinedExprClass:
+            zig_panic("TODO handle C PredefinedExprClass");
+        case Stmt::PseudoObjectExprClass:
+            zig_panic("TODO handle C PseudoObjectExprClass");
+        case Stmt::ShuffleVectorExprClass:
+            zig_panic("TODO handle C ShuffleVectorExprClass");
+        case Stmt::SizeOfPackExprClass:
+            zig_panic("TODO handle C SizeOfPackExprClass");
+        case Stmt::StmtExprClass:
+            zig_panic("TODO handle C StmtExprClass");
+        case Stmt::StringLiteralClass:
+            zig_panic("TODO handle C StringLiteralClass");
+        case Stmt::SubstNonTypeTemplateParmExprClass:
+            zig_panic("TODO handle C SubstNonTypeTemplateParmExprClass");
+        case Stmt::SubstNonTypeTemplateParmPackExprClass:
+            zig_panic("TODO handle C SubstNonTypeTemplateParmPackExprClass");
+        case Stmt::TypeTraitExprClass:
+            zig_panic("TODO handle C TypeTraitExprClass");
+        case Stmt::TypoExprClass:
+            zig_panic("TODO handle C TypoExprClass");
+        case Stmt::UnaryExprOrTypeTraitExprClass:
+            zig_panic("TODO handle C UnaryExprOrTypeTraitExprClass");
+        case Stmt::UnaryOperatorClass:
+            zig_panic("TODO handle C UnaryOperatorClass");
+        case Stmt::VAArgExprClass:
+            zig_panic("TODO handle C VAArgExprClass");
+        case Stmt::ForStmtClass:
+            zig_panic("TODO handle C ForStmtClass");
+        case Stmt::GotoStmtClass:
+            zig_panic("TODO handle C GotoStmtClass");
+        case Stmt::IfStmtClass:
+            zig_panic("TODO handle C IfStmtClass");
+        case Stmt::IndirectGotoStmtClass:
+            zig_panic("TODO handle C IndirectGotoStmtClass");
+        case Stmt::LabelStmtClass:
+            zig_panic("TODO handle C LabelStmtClass");
+        case Stmt::MSDependentExistsStmtClass:
+            zig_panic("TODO handle C MSDependentExistsStmtClass");
+        case Stmt::NullStmtClass:
+            zig_panic("TODO handle C NullStmtClass");
+        case Stmt::OMPAtomicDirectiveClass:
+            zig_panic("TODO handle C OMPAtomicDirectiveClass");
+        case Stmt::OMPBarrierDirectiveClass:
+            zig_panic("TODO handle C OMPBarrierDirectiveClass");
+        case Stmt::OMPCancelDirectiveClass:
+            zig_panic("TODO handle C OMPCancelDirectiveClass");
+        case Stmt::OMPCancellationPointDirectiveClass:
+            zig_panic("TODO handle C OMPCancellationPointDirectiveClass");
+        case Stmt::OMPCriticalDirectiveClass:
+            zig_panic("TODO handle C OMPCriticalDirectiveClass");
+        case Stmt::OMPFlushDirectiveClass:
+            zig_panic("TODO handle C OMPFlushDirectiveClass");
+        case Stmt::OMPDistributeDirectiveClass:
+            zig_panic("TODO handle C OMPDistributeDirectiveClass");
+        case Stmt::OMPDistributeParallelForDirectiveClass:
+            zig_panic("TODO handle C OMPDistributeParallelForDirectiveClass");
+        case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPDistributeParallelForSimdDirectiveClass");
+        case Stmt::OMPDistributeSimdDirectiveClass:
+            zig_panic("TODO handle C OMPDistributeSimdDirectiveClass");
+        case Stmt::OMPForDirectiveClass:
+            zig_panic("TODO handle C OMPForDirectiveClass");
+        case Stmt::OMPForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPForSimdDirectiveClass");
+        case Stmt::OMPParallelForDirectiveClass:
+            zig_panic("TODO handle C OMPParallelForDirectiveClass");
+        case Stmt::OMPParallelForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPParallelForSimdDirectiveClass");
+        case Stmt::OMPSimdDirectiveClass:
+            zig_panic("TODO handle C OMPSimdDirectiveClass");
+        case Stmt::OMPTargetParallelForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTargetParallelForSimdDirectiveClass");
+        case Stmt::OMPTargetSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTargetSimdDirectiveClass");
+        case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+            zig_panic("TODO handle C OMPTargetTeamsDistributeDirectiveClass");
+        case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+            zig_panic("TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass");
+        case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass");
+        case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass");
+        case Stmt::OMPTaskLoopDirectiveClass:
+            zig_panic("TODO handle C OMPTaskLoopDirectiveClass");
+        case Stmt::OMPTaskLoopSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTaskLoopSimdDirectiveClass");
+        case Stmt::OMPTeamsDistributeDirectiveClass:
+            zig_panic("TODO handle C OMPTeamsDistributeDirectiveClass");
+        case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+            zig_panic("TODO handle C OMPTeamsDistributeParallelForDirectiveClass");
+        case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass");
+        case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+            zig_panic("TODO handle C OMPTeamsDistributeSimdDirectiveClass");
+        case Stmt::OMPMasterDirectiveClass:
+            zig_panic("TODO handle C OMPMasterDirectiveClass");
+        case Stmt::OMPOrderedDirectiveClass:
+            zig_panic("TODO handle C OMPOrderedDirectiveClass");
+        case Stmt::OMPParallelDirectiveClass:
+            zig_panic("TODO handle C OMPParallelDirectiveClass");
+        case Stmt::OMPParallelSectionsDirectiveClass:
+            zig_panic("TODO handle C OMPParallelSectionsDirectiveClass");
+        case Stmt::OMPSectionDirectiveClass:
+            zig_panic("TODO handle C OMPSectionDirectiveClass");
+        case Stmt::OMPSectionsDirectiveClass:
+            zig_panic("TODO handle C OMPSectionsDirectiveClass");
+        case Stmt::OMPSingleDirectiveClass:
+            zig_panic("TODO handle C OMPSingleDirectiveClass");
+        case Stmt::OMPTargetDataDirectiveClass:
+            zig_panic("TODO handle C OMPTargetDataDirectiveClass");
+        case Stmt::OMPTargetDirectiveClass:
+            zig_panic("TODO handle C OMPTargetDirectiveClass");
+        case Stmt::OMPTargetEnterDataDirectiveClass:
+            zig_panic("TODO handle C OMPTargetEnterDataDirectiveClass");
+        case Stmt::OMPTargetExitDataDirectiveClass:
+            zig_panic("TODO handle C OMPTargetExitDataDirectiveClass");
+        case Stmt::OMPTargetParallelDirectiveClass:
+            zig_panic("TODO handle C OMPTargetParallelDirectiveClass");
+        case Stmt::OMPTargetParallelForDirectiveClass:
+            zig_panic("TODO handle C OMPTargetParallelForDirectiveClass");
+        case Stmt::OMPTargetTeamsDirectiveClass:
+            zig_panic("TODO handle C OMPTargetTeamsDirectiveClass");
+        case Stmt::OMPTargetUpdateDirectiveClass:
+            zig_panic("TODO handle C OMPTargetUpdateDirectiveClass");
+        case Stmt::OMPTaskDirectiveClass:
+            zig_panic("TODO handle C OMPTaskDirectiveClass");
+        case Stmt::OMPTaskgroupDirectiveClass:
+            zig_panic("TODO handle C OMPTaskgroupDirectiveClass");
+        case Stmt::OMPTaskwaitDirectiveClass:
+            zig_panic("TODO handle C OMPTaskwaitDirectiveClass");
+        case Stmt::OMPTaskyieldDirectiveClass:
+            zig_panic("TODO handle C OMPTaskyieldDirectiveClass");
+        case Stmt::OMPTeamsDirectiveClass:
+            zig_panic("TODO handle C OMPTeamsDirectiveClass");
+        case Stmt::ObjCAtCatchStmtClass:
+            zig_panic("TODO handle C ObjCAtCatchStmtClass");
+        case Stmt::ObjCAtFinallyStmtClass:
+            zig_panic("TODO handle C ObjCAtFinallyStmtClass");
+        case Stmt::ObjCAtSynchronizedStmtClass:
+            zig_panic("TODO handle C ObjCAtSynchronizedStmtClass");
+        case Stmt::ObjCAtThrowStmtClass:
+            zig_panic("TODO handle C ObjCAtThrowStmtClass");
+        case Stmt::ObjCAtTryStmtClass:
+            zig_panic("TODO handle C ObjCAtTryStmtClass");
+        case Stmt::ObjCAutoreleasePoolStmtClass:
+            zig_panic("TODO handle C ObjCAutoreleasePoolStmtClass");
+        case Stmt::ObjCForCollectionStmtClass:
+            zig_panic("TODO handle C ObjCForCollectionStmtClass");
+        case Stmt::SEHExceptStmtClass:
+            zig_panic("TODO handle C SEHExceptStmtClass");
+        case Stmt::SEHFinallyStmtClass:
+            zig_panic("TODO handle C SEHFinallyStmtClass");
+        case Stmt::SEHLeaveStmtClass:
+            zig_panic("TODO handle C SEHLeaveStmtClass");
+        case Stmt::SEHTryStmtClass:
+            zig_panic("TODO handle C SEHTryStmtClass");
+    }
+    zig_unreachable();
+}
+
 static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
     Buf *fn_name = buf_create_from_str(decl_name(fn_decl));
 
+    if (fn_decl->hasBody()) {
+        fprintf(stderr, "fn %s\n", buf_ptr(fn_name));
+        Stmt *body = fn_decl->getBody();
+        AstNode *body_node = ast_trans_stmt(c, body);
+        ast_render(c->codegen, stderr, body_node, 4);
+        fprintf(stderr, "\n");
+    }
+
     if (get_global(c, fn_name)) {
         // we already saw this function
         return;
@@ -1373,7 +1843,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
 
     std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>();
 
-    bool skip_function_bodies = true;
+    bool skip_function_bodies = false;
     bool only_local_decls = true;
     bool capture_diagnostics = true;
     bool user_files_are_volatile = true;
@@ -1390,7 +1860,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
             single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit,
             nullptr));
 
-
     // Early failures in LoadFromCommandLine may return with ErrUnit unset.
     if (!ast_unit && !err_unit) {
         return ErrorFileSystem;
@@ -1416,29 +1885,36 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
                     break;
             }
             StringRef msg_str_ref = it->getMessage();
-            FullSourceLoc fsl = it->getLocation();
-            FileID file_id = fsl.getFileID();
-            StringRef filename = fsl.getManager().getFilename(fsl);
-            unsigned line = fsl.getSpellingLineNumber() - 1;
-            unsigned column = fsl.getSpellingColumnNumber() - 1;
-            unsigned offset = fsl.getManager().getFileOffset(fsl);
-            const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
             Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
-            Buf *path;
-            if (filename.empty()) {
-                path = buf_alloc();
-            } else {
-                path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
-            }
+            FullSourceLoc fsl = it->getLocation();
+            if (fsl.hasManager()) {
+                FileID file_id = fsl.getFileID();
+                StringRef filename = fsl.getManager().getFilename(fsl);
+                unsigned line = fsl.getSpellingLineNumber() - 1;
+                unsigned column = fsl.getSpellingColumnNumber() - 1;
+                unsigned offset = fsl.getManager().getFileOffset(fsl);
+                const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
+                Buf *path;
+                if (filename.empty()) {
+                    path = buf_alloc();
+                } else {
+                    path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
+                }
 
-            ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
+                ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
 
-            c->errors->append(err_msg);
+                c->errors->append(err_msg);
+            } else {
+                // NOTE the only known way this gets triggered right now is if you have a lot of errors
+                // clang emits "too many errors emitted, stopping now"
+                fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg));
+            }
         }
 
         return 0;
     }
 
+    c->ctx = &ast_unit->getASTContext();
     c->source_manager = &ast_unit->getSourceManager();
 
     ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
src/parser.cpp
@@ -20,7 +20,6 @@ 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;
@@ -70,8 +69,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;
 }
 
@@ -2611,7 +2608,7 @@ 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");
@@ -2620,7 +2617,6 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
     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;
src/parser.hpp
@@ -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);
 
std/zlib/deflate.zig
@@ -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;
+}
std/zlib/inflate.zig
@@ -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;
+}