From ee9d1d0414ac6cc877e86055dcb08543db9b57ad Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Sep 2017 03:16:35 -0400 Subject: [PATCH 01/16] c-to-zig: return statement --- src/all_types.hpp | 2 - src/analyze.cpp | 3 +- src/parseh.cpp | 510 ++++++++++++++++++++++- src/parser.cpp | 6 +- src/parser.hpp | 3 +- std/zlib/deflate.zig | 522 +++++++++++++++++++++++ std/zlib/inflate.zig | 969 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1987 insertions(+), 28 deletions(-) create mode 100644 std/zlib/deflate.zig create mode 100644 std/zlib/inflate.zig diff --git a/src/all_types.hpp b/src/all_types.hpp index 39e6033988..e785e61c1b 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/analyze.cpp b/src/analyze.cpp index 041d4eea70..b3e9601102 100644 --- a/src/analyze.cpp +++ b/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); diff --git a/src/parseh.cpp b/src/parseh.cpp index 9acbc7c57c..0d8bfd9dfe 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -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(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(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 *errors, const ch std::shared_ptr pch_container_ops = std::make_shared(); - 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 *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 *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(); + 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); + + c->errors->append(err_msg); } else { - path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size()); + // 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)); } - - ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); - - c->errors->append(err_msg); } return 0; } + c->ctx = &ast_unit->getASTContext(); c->source_manager = &ast_unit->getSourceManager(); ast_unit->visitLocalTopLevelDecls(c, decl_visitor); diff --git a/src/parser.cpp b/src/parser.cpp index 7961953aff..75d4dd309c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -20,7 +20,6 @@ struct ParseContext { ZigList *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(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 *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 *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; diff --git a/src/parser.hpp b/src/parser.hpp index 2fe30ec4b4..c95413309f 100644 --- a/src/parser.hpp +++ b/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 *tokens, ImportTableEntry *owner, ErrColor err_color, - uint32_t *next_node_index); +AstNode * ast_parse(Buf *buf, ZigList *tokens, ImportTableEntry *owner, ErrColor err_color); void ast_print(AstNode *node, int indent); diff --git a/std/zlib/deflate.zig b/std/zlib/deflate.zig new file mode 100644 index 0000000000..7374d33cf1 --- /dev/null +++ b/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; +} diff --git a/std/zlib/inflate.zig b/std/zlib/inflate.zig new file mode 100644 index 0000000000..1bb3f858ac --- /dev/null +++ b/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; +} From 46e9d9df51ee0c0d094c4b428bbb8d2c820b99fd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Sep 2017 04:38:57 -0400 Subject: [PATCH 02/16] c-to-zig: less than, negation, ternary --- src/parseh.cpp | 403 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 372 insertions(+), 31 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 0d8bfd9dfe..48a23a90b6 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -276,18 +276,22 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const return get_c_int_type(c->codegen, CIntTypeLong); case BuiltinType::LongLong: return get_c_int_type(c->codegen, CIntTypeLongLong); + case BuiltinType::UInt128: + return c->codegen->builtin_types.entry_u128; + case BuiltinType::Int128: + return c->codegen->builtin_types.entry_i128; case BuiltinType::Float: return c->codegen->builtin_types.entry_f32; case BuiltinType::Double: return c->codegen->builtin_types.entry_f64; + case BuiltinType::Float128: + return c->codegen->builtin_types.entry_f128; case BuiltinType::LongDouble: return c->codegen->builtin_types.entry_c_longdouble; case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: - case BuiltinType::UInt128: case BuiltinType::WChar_S: - case BuiltinType::Int128: case BuiltinType::Half: case BuiltinType::NullPtr: case BuiltinType::ObjCId: @@ -338,7 +342,6 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const case BuiltinType::OCLImage2dMSAADepthRW: case BuiltinType::OCLImage2dArrayMSAADepthRW: case BuiltinType::OCLImage3dRW: - case BuiltinType::Float128: case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: @@ -606,13 +609,70 @@ static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *de #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 bool c_is_signed_integer(Context *c, QualType qt) { + const Type *c_type = qt.getTypePtr(); + if (c_type->getTypeClass() != Type::Builtin) + return false; + const BuiltinType *builtin_ty = static_cast(c_type); + switch (builtin_ty->getKind()) { + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::WChar_S: + return true; + default: + return false; + } } -static AstNode * ast_create_node(Context *c, const SourceRange &range, NodeType id) { +static bool c_is_unsigned_integer(Context *c, QualType qt) { + const Type *c_type = qt.getTypePtr(); + if (c_type->getTypeClass() != Type::Builtin) + return false; + const BuiltinType *builtin_ty = static_cast(c_type); + switch (builtin_ty->getKind()) { + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::WChar_U: + return true; + default: + return false; + } +} + +static bool c_is_float(Context *c, QualType qt) { + const Type *c_type = qt.getTypePtr(); + if (c_type->getTypeClass() != Type::Builtin) + return false; + const BuiltinType *builtin_ty = static_cast(c_type); + switch (builtin_ty->getKind()) { + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::Float128: + case BuiltinType::LongDouble: + return true; + default: + return false; + } +} + +static AstNode * trans_stmt(Context *c, Stmt *stmt); + +static AstNode * trans_expr(Context *c, Expr *expr) { + return trans_stmt(c, expr); +} + +static AstNode * trans_create_node(Context *c, Stmt *stmt, NodeType id) { AstNode *node = allocate(1); node->type = id; node->owner = c->import; @@ -620,22 +680,22 @@ static AstNode * ast_create_node(Context *c, const SourceRange &range, NodeType return node; } -static AstNode * ast_trans_compound_stmt(Context *c, CompoundStmt *stmt) { - AstNode *block_node = ast_create_node(c, stmt->getSourceRange(), NodeTypeBlock); +static AstNode * trans_compound_stmt(Context *c, CompoundStmt *stmt) { + AstNode *block_node = trans_create_node(c, stmt, 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); + AstNode *child_node = 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) { +static AstNode *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); + AstNode *return_node = trans_create_node(c, stmt, NodeTypeReturnExpr); + return_node->data.return_expr.expr = trans_expr(c, value_expr); return return_node; } } @@ -656,8 +716,9 @@ static void aps_int_to_bigint(Context *c, const llvm::APSInt &aps_int, BigInt *b } } } -static AstNode * ast_trans_integer_literal(Context *c, IntegerLiteral *stmt) { - AstNode *node = ast_create_node(c, stmt->getSourceRange(), NodeTypeIntLiteral); + +static AstNode * trans_integer_literal(Context *c, IntegerLiteral *stmt) { + AstNode *node = trans_create_node(c, stmt, NodeTypeIntLiteral); llvm::APSInt result; if (!stmt->EvaluateAsInt(result, *c->ctx)) { fprintf(stderr, "TODO unable to convert integer literal to zig\n"); @@ -667,15 +728,305 @@ static AstNode * ast_trans_integer_literal(Context *c, IntegerLiteral *stmt) { return node; } -static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { +static AstNode * trans_conditional_operator(Context *c, ConditionalOperator *stmt) { + AstNode *node = trans_create_node(c, stmt, NodeTypeIfBoolExpr); + + Expr *cond_expr = stmt->getCond(); + Expr *true_expr = stmt->getTrueExpr(); + Expr *false_expr = stmt->getFalseExpr(); + + node->data.if_bool_expr.condition = trans_expr(c, cond_expr); + node->data.if_bool_expr.then_block = trans_expr(c, true_expr); + node->data.if_bool_expr.else_node = trans_expr(c, false_expr); + + return node; +} + +static AstNode * trans_binary_operator(Context *c, BinaryOperator *stmt) { + switch (stmt->getOpcode()) { + case BO_PtrMemD: + zig_panic("TODO handle more C binary operators: BO_PtrMemD"); + case BO_PtrMemI: + zig_panic("TODO handle more C binary operators: BO_PtrMemI"); + case BO_Mul: + zig_panic("TODO handle more C binary operators: BO_Mul"); + case BO_Div: + zig_panic("TODO handle more C binary operators: BO_Div"); + case BO_Rem: + zig_panic("TODO handle more C binary operators: BO_Rem"); + case BO_Add: + zig_panic("TODO handle more C binary operators: BO_Add"); + case BO_Sub: + zig_panic("TODO handle more C binary operators: BO_Sub"); + case BO_Shl: + zig_panic("TODO handle more C binary operators: BO_Shl"); + case BO_Shr: + zig_panic("TODO handle more C binary operators: BO_Shr"); + case BO_LT: + { + AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); + node->data.bin_op_expr.bin_op = BinOpTypeCmpLessThan; + node->data.bin_op_expr.op1 = trans_expr(c, stmt->getLHS()); + node->data.bin_op_expr.op2 = trans_expr(c, stmt->getRHS()); + return node; + } + case BO_GT: + zig_panic("TODO handle more C binary operators: BO_GT"); + case BO_LE: + zig_panic("TODO handle more C binary operators: BO_LE"); + case BO_GE: + zig_panic("TODO handle more C binary operators: BO_GE"); + case BO_EQ: + zig_panic("TODO handle more C binary operators: BO_EQ"); + case BO_NE: + zig_panic("TODO handle more C binary operators: BO_NE"); + case BO_And: + zig_panic("TODO handle more C binary operators: BO_And"); + case BO_Xor: + zig_panic("TODO handle more C binary operators: BO_Xor"); + case BO_Or: + zig_panic("TODO handle more C binary operators: BO_Or"); + case BO_LAnd: + zig_panic("TODO handle more C binary operators: BO_LAnd"); + case BO_LOr: + zig_panic("TODO handle more C binary operators: BO_LOr"); + case BO_Assign: + zig_panic("TODO handle more C binary operators: BO_Assign"); + case BO_MulAssign: + zig_panic("TODO handle more C binary operators: BO_MulAssign"); + case BO_DivAssign: + zig_panic("TODO handle more C binary operators: BO_DivAssign"); + case BO_RemAssign: + zig_panic("TODO handle more C binary operators: BO_RemAssign"); + case BO_AddAssign: + zig_panic("TODO handle more C binary operators: BO_AddAssign"); + case BO_SubAssign: + zig_panic("TODO handle more C binary operators: BO_SubAssign"); + case BO_ShlAssign: + zig_panic("TODO handle more C binary operators: BO_ShlAssign"); + case BO_ShrAssign: + zig_panic("TODO handle more C binary operators: BO_ShrAssign"); + case BO_AndAssign: + zig_panic("TODO handle more C binary operators: BO_AndAssign"); + case BO_XorAssign: + zig_panic("TODO handle more C binary operators: BO_XorAssign"); + case BO_OrAssign: + zig_panic("TODO handle more C binary operators: BO_OrAssign"); + case BO_Comma: + zig_panic("TODO handle more C binary operators: BO_Comma"); + } + + zig_unreachable(); +} + +static AstNode * trans_implicit_cast_expr(Context *c, ImplicitCastExpr *stmt) { + switch (stmt->getCastKind()) { + case CK_LValueToRValue: + return trans_expr(c, stmt->getSubExpr()); + case CK_Dependent: + zig_panic("TODO handle C translation cast CK_Dependent"); + case CK_BitCast: + zig_panic("TODO handle C translation cast CK_BitCast"); + case CK_LValueBitCast: + zig_panic("TODO handle C translation cast CK_LValueBitCast"); + case CK_NoOp: + zig_panic("TODO handle C translation cast CK_NoOp"); + case CK_BaseToDerived: + zig_panic("TODO handle C translation cast CK_BaseToDerived"); + case CK_DerivedToBase: + zig_panic("TODO handle C translation cast CK_DerivedToBase"); + case CK_UncheckedDerivedToBase: + zig_panic("TODO handle C translation cast CK_UncheckedDerivedToBase"); + case CK_Dynamic: + zig_panic("TODO handle C translation cast CK_Dynamic"); + case CK_ToUnion: + zig_panic("TODO handle C translation cast CK_ToUnion"); + case CK_ArrayToPointerDecay: + zig_panic("TODO handle C translation cast CK_ArrayToPointerDecay"); + case CK_FunctionToPointerDecay: + zig_panic("TODO handle C translation cast CK_FunctionToPointerDecay"); + case CK_NullToPointer: + zig_panic("TODO handle C translation cast CK_NullToPointer"); + case CK_NullToMemberPointer: + zig_panic("TODO handle C translation cast CK_NullToMemberPointer"); + case CK_BaseToDerivedMemberPointer: + zig_panic("TODO handle C translation cast CK_BaseToDerivedMemberPointer"); + case CK_DerivedToBaseMemberPointer: + zig_panic("TODO handle C translation cast CK_DerivedToBaseMemberPointer"); + case CK_MemberPointerToBoolean: + zig_panic("TODO handle C translation cast CK_MemberPointerToBoolean"); + case CK_ReinterpretMemberPointer: + zig_panic("TODO handle C translation cast CK_ReinterpretMemberPointer"); + case CK_UserDefinedConversion: + zig_panic("TODO handle C translation cast CK_UserDefinedConversion"); + case CK_ConstructorConversion: + zig_panic("TODO handle C translation cast CK_ConstructorConversion"); + case CK_IntegralToPointer: + zig_panic("TODO handle C translation cast CK_IntegralToPointer"); + case CK_PointerToIntegral: + zig_panic("TODO handle C translation cast CK_PointerToIntegral"); + case CK_PointerToBoolean: + zig_panic("TODO handle C translation cast CK_PointerToBoolean"); + case CK_ToVoid: + zig_panic("TODO handle C translation cast CK_ToVoid"); + case CK_VectorSplat: + zig_panic("TODO handle C translation cast CK_VectorSplat"); + case CK_IntegralCast: + zig_panic("TODO handle C translation cast CK_IntegralCast"); + case CK_IntegralToBoolean: + zig_panic("TODO handle C translation cast CK_IntegralToBoolean"); + case CK_IntegralToFloating: + zig_panic("TODO handle C translation cast CK_IntegralToFloating"); + case CK_FloatingToIntegral: + zig_panic("TODO handle C translation cast CK_FloatingToIntegral"); + case CK_FloatingToBoolean: + zig_panic("TODO handle C translation cast CK_FloatingToBoolean"); + case CK_BooleanToSignedIntegral: + zig_panic("TODO handle C translation cast CK_BooleanToSignedIntegral"); + case CK_FloatingCast: + zig_panic("TODO handle C translation cast CK_FloatingCast"); + case CK_CPointerToObjCPointerCast: + zig_panic("TODO handle C translation cast CK_CPointerToObjCPointerCast"); + case CK_BlockPointerToObjCPointerCast: + zig_panic("TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); + case CK_AnyPointerToBlockPointerCast: + zig_panic("TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); + case CK_ObjCObjectLValueCast: + zig_panic("TODO handle C translation cast CK_ObjCObjectLValueCast"); + case CK_FloatingRealToComplex: + zig_panic("TODO handle C translation cast CK_FloatingRealToComplex"); + case CK_FloatingComplexToReal: + zig_panic("TODO handle C translation cast CK_FloatingComplexToReal"); + case CK_FloatingComplexToBoolean: + zig_panic("TODO handle C translation cast CK_FloatingComplexToBoolean"); + case CK_FloatingComplexCast: + zig_panic("TODO handle C translation cast CK_FloatingComplexCast"); + case CK_FloatingComplexToIntegralComplex: + zig_panic("TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); + case CK_IntegralRealToComplex: + zig_panic("TODO handle C translation cast CK_IntegralRealToComplex"); + case CK_IntegralComplexToReal: + zig_panic("TODO handle C translation cast CK_IntegralComplexToReal"); + case CK_IntegralComplexToBoolean: + zig_panic("TODO handle C translation cast CK_IntegralComplexToBoolean"); + case CK_IntegralComplexCast: + zig_panic("TODO handle C translation cast CK_IntegralComplexCast"); + case CK_IntegralComplexToFloatingComplex: + zig_panic("TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); + case CK_ARCProduceObject: + zig_panic("TODO handle C translation cast CK_ARCProduceObject"); + case CK_ARCConsumeObject: + zig_panic("TODO handle C translation cast CK_ARCConsumeObject"); + case CK_ARCReclaimReturnedObject: + zig_panic("TODO handle C translation cast CK_ARCReclaimReturnedObject"); + case CK_ARCExtendBlockObject: + zig_panic("TODO handle C translation cast CK_ARCExtendBlockObject"); + case CK_AtomicToNonAtomic: + zig_panic("TODO handle C translation cast CK_AtomicToNonAtomic"); + case CK_NonAtomicToAtomic: + zig_panic("TODO handle C translation cast CK_NonAtomicToAtomic"); + case CK_CopyAndAutoreleaseBlockObject: + zig_panic("TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); + case CK_BuiltinFnToFnPtr: + zig_panic("TODO handle C translation cast CK_BuiltinFnToFnPtr"); + case CK_ZeroToOCLEvent: + zig_panic("TODO handle C translation cast CK_ZeroToOCLEvent"); + case CK_ZeroToOCLQueue: + zig_panic("TODO handle C translation cast CK_ZeroToOCLQueue"); + case CK_AddressSpaceConversion: + zig_panic("TODO handle C translation cast CK_AddressSpaceConversion"); + case CK_IntToOCLSampler: + zig_panic("TODO handle C translation cast CK_IntToOCLSampler"); + } + zig_unreachable(); +} + +static AstNode * trans_decl_ref_expr(Context *c, DeclRefExpr *stmt) { + ValueDecl *value_decl = stmt->getDecl(); + const char *name = decl_name(value_decl); + + AstNode *node = trans_create_node(c, stmt, NodeTypeSymbol); + node->data.symbol_expr.symbol = buf_create_from_str(name); + return node; +} + +static AstNode * trans_create_num_lit_node_unsigned(Context *c, Stmt *stmt, uint64_t x) { + AstNode *node = trans_create_node(c, stmt, NodeTypeIntLiteral); + node->data.int_literal.bigint = allocate(1); + bigint_init_unsigned(node->data.int_literal.bigint, x); + return node; +} + +static AstNode * trans_unary_operator(Context *c, UnaryOperator *stmt) { + switch (stmt->getOpcode()) { + case UO_PostInc: + zig_panic("TODO handle C translation UO_PostInc"); + case UO_PostDec: + zig_panic("TODO handle C translation UO_PostDec"); + case UO_PreInc: + zig_panic("TODO handle C translation UO_PreInc"); + case UO_PreDec: + zig_panic("TODO handle C translation UO_PreDec"); + case UO_AddrOf: + zig_panic("TODO handle C translation UO_AddrOf"); + case UO_Deref: + zig_panic("TODO handle C translation UO_Deref"); + case UO_Plus: + zig_panic("TODO handle C translation UO_Plus"); + case UO_Minus: + { + Expr *op_expr = stmt->getSubExpr(); + if (c_is_signed_integer(c, op_expr->getType()) || c_is_float(c, op_expr->getType())) { + AstNode *node = trans_create_node(c, stmt, NodeTypePrefixOpExpr); + node->data.prefix_op_expr.prefix_op = PrefixOpNegation; + node->data.prefix_op_expr.primary_expr = trans_expr(c, op_expr); + return node; + } else if (c_is_unsigned_integer(c, op_expr->getType())) { + // we gotta emit 0 -% x + AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); + node->data.bin_op_expr.op1 = trans_create_num_lit_node_unsigned(c, stmt, 0); + node->data.bin_op_expr.op2 = trans_expr(c, op_expr); + node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; + return node; + } else { + zig_panic("TODO translate C negation with non float non integer"); + } + } + case UO_Not: + zig_panic("TODO handle C translation UO_Not"); + case UO_LNot: + zig_panic("TODO handle C translation UO_LNot"); + case UO_Real: + zig_panic("TODO handle C translation UO_Real"); + case UO_Imag: + zig_panic("TODO handle C translation UO_Imag"); + case UO_Extension: + zig_panic("TODO handle C translation UO_Extension"); + case UO_Coawait: + zig_panic("TODO handle C translation UO_Coawait"); + } + zig_unreachable(); +} + +static AstNode *trans_stmt(Context *c, Stmt *stmt) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { case Stmt::ReturnStmtClass: - return ast_trans_return_stmt(c, (ReturnStmt *)stmt); + return trans_return_stmt(c, (ReturnStmt *)stmt); case Stmt::CompoundStmtClass: - return ast_trans_compound_stmt(c, (CompoundStmt *)stmt); + return trans_compound_stmt(c, (CompoundStmt *)stmt); case Stmt::IntegerLiteralClass: - return ast_trans_integer_literal(c, (IntegerLiteral *)stmt); + return trans_integer_literal(c, (IntegerLiteral *)stmt); + case Stmt::ConditionalOperatorClass: + return trans_conditional_operator(c, (ConditionalOperator *)stmt); + case Stmt::BinaryOperatorClass: + return trans_binary_operator(c, (BinaryOperator *)stmt); + case Stmt::ImplicitCastExprClass: + return trans_implicit_cast_expr(c, (ImplicitCastExpr *)stmt); + case Stmt::DeclRefExprClass: + return trans_decl_ref_expr(c, (DeclRefExpr *)stmt); + case Stmt::UnaryOperatorClass: + return trans_unary_operator(c, (UnaryOperator *)stmt); case Stmt::CaseStmtClass: zig_panic("TODO handle C CaseStmtClass"); case Stmt::DefaultStmtClass: @@ -714,8 +1065,6 @@ static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { 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: @@ -730,8 +1079,6 @@ static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { 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: @@ -802,8 +1149,6 @@ static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { 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: @@ -816,8 +1161,6 @@ static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { 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: @@ -926,8 +1269,6 @@ static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) { 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: @@ -1070,7 +1411,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *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); + AstNode *body_node = trans_stmt(c, body); ast_render(c->codegen, stderr, body_node, 4); fprintf(stderr, "\n"); } From 60bdbe540538867315038305c6f41020b44036c2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Sep 2017 13:39:16 -0400 Subject: [PATCH 03/16] parseh: emit_warning takes SourceLocation --- src/parseh.cpp | 86 ++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 48a23a90b6..52b75e1b1a 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -67,7 +67,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); __attribute__ ((format (printf, 3, 4))) -static void emit_warning(Context *c, const Decl *decl, const char *format, ...) { +static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { if (!c->warnings_on) { return; } @@ -77,8 +77,6 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...) Buf *msg = buf_vprintf(format, ap); va_end(ap); - SourceLocation sl = decl->getLocation(); - StringRef filename = c->source_manager->getFilename(sl); const char *filename_bytes = (const char *)filename.bytes_begin(); Buf *path; @@ -185,14 +183,14 @@ static ConstExprValue *create_const_int_ap(Context *c, TypeTableEntry *type, con { if (aps_int.isSigned()) { if (aps_int > INT64_MAX || aps_int < INT64_MIN) { - emit_warning(c, source_decl, "integer overflow\n"); + emit_warning(c, source_decl->getLocation(), "integer overflow\n"); return nullptr; } else { return create_const_signed(type, aps_int.getExtValue()); } } else { if (aps_int > INT64_MAX) { - emit_warning(c, source_decl, "integer overflow\n"); + emit_warning(c, source_decl->getLocation(), "integer overflow\n"); return nullptr; } else { return create_const_unsigned_negative(type, aps_int.getExtValue(), false); @@ -347,7 +345,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: - emit_warning(c, decl, "missed a builtin type"); + emit_warning(c, decl->getLocation(), "missed a builtin type"); return c->codegen->builtin_types.entry_invalid; } break; @@ -358,7 +356,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const QualType child_qt = pointer_ty->getPointeeType(); TypeTableEntry *child_type = resolve_qual_type(c, child_qt, decl); if (type_is_invalid(child_type)) { - emit_warning(c, decl, "pointer to unresolved type"); + emit_warning(c, decl->getLocation(), "pointer to unresolved type"); return c->codegen->builtin_types.entry_invalid; } @@ -423,7 +421,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const case ETK_Class: case ETK_Typename: case ETK_None: - emit_warning(c, decl, "unsupported elaborated type"); + emit_warning(c, decl->getLocation(), "unsupported elaborated type"); return c->codegen->builtin_types.entry_invalid; } } @@ -435,52 +433,52 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const case CC_C: // __attribute__((cdecl)) break; case CC_X86StdCall: // __attribute__((stdcall)) - emit_warning(c, decl, "function type has x86 stdcall calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 stdcall calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86FastCall: // __attribute__((fastcall)) - emit_warning(c, decl, "function type has x86 fastcall calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 fastcall calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86ThisCall: // __attribute__((thiscall)) - emit_warning(c, decl, "function type has x86 thiscall calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 thiscall calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86VectorCall: // __attribute__((vectorcall)) - emit_warning(c, decl, "function type has x86 vectorcall calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 vectorcall calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86Pascal: // __attribute__((pascal)) - emit_warning(c, decl, "function type has x86 pascal calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 pascal calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_Win64: // __attribute__((ms_abi)) - emit_warning(c, decl, "function type has win64 calling convention"); + emit_warning(c, decl->getLocation(), "function type has win64 calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86_64SysV: // __attribute__((sysv_abi)) - emit_warning(c, decl, "function type has x86 64sysv calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 64sysv calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_X86RegCall: - emit_warning(c, decl, "function type has x86 reg calling convention"); + emit_warning(c, decl->getLocation(), "function type has x86 reg calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_AAPCS: // __attribute__((pcs("aapcs"))) - emit_warning(c, decl, "function type has aapcs calling convention"); + emit_warning(c, decl->getLocation(), "function type has aapcs calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) - emit_warning(c, decl, "function type has aapcs-vfp calling convention"); + emit_warning(c, decl->getLocation(), "function type has aapcs-vfp calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) - emit_warning(c, decl, "function type has intel_ocl_bicc calling convention"); + emit_warning(c, decl->getLocation(), "function type has intel_ocl_bicc calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_SpirFunction: // default for OpenCL functions on SPIR target - emit_warning(c, decl, "function type has SPIR function calling convention"); + emit_warning(c, decl->getLocation(), "function type has SPIR function calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_OpenCLKernel: - emit_warning(c, decl, "function type has OpenCLKernel calling convention"); + emit_warning(c, decl->getLocation(), "function type has OpenCLKernel calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_Swift: - emit_warning(c, decl, "function type has Swift calling convention"); + emit_warning(c, decl->getLocation(), "function type has Swift calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_PreserveMost: - emit_warning(c, decl, "function type has PreserveMost calling convention"); + emit_warning(c, decl->getLocation(), "function type has PreserveMost calling convention"); return c->codegen->builtin_types.entry_invalid; case CC_PreserveAll: - emit_warning(c, decl, "function type has PreserveAll calling convention"); + emit_warning(c, decl->getLocation(), "function type has PreserveAll calling convention"); return c->codegen->builtin_types.entry_invalid; } @@ -495,7 +493,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const } else { fn_type_id.return_type = resolve_qual_type(c, fn_proto_ty->getReturnType(), decl); if (type_is_invalid(fn_type_id.return_type)) { - emit_warning(c, decl, "unresolved function proto return type"); + emit_warning(c, decl->getLocation(), "unresolved function proto return type"); return c->codegen->builtin_types.entry_invalid; } // convert c_void to actual void (only for return type) @@ -510,7 +508,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const TypeTableEntry *param_type = resolve_qual_type(c, qt, decl); if (type_is_invalid(param_type)) { - emit_warning(c, decl, "unresolved function proto parameter type"); + emit_warning(c, decl->getLocation(), "unresolved function proto parameter type"); return c->codegen->builtin_types.entry_invalid; } @@ -536,7 +534,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const const ConstantArrayType *const_arr_ty = static_cast(ty); TypeTableEntry *child_type = resolve_qual_type(c, const_arr_ty->getElementType(), decl); if (child_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, decl, "unresolved array element type"); + emit_warning(c, decl->getLocation(), "unresolved array element type"); return child_type; } uint64_t size = const_arr_ty->getSize().getLimitedValue(); @@ -591,7 +589,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const case Type::Pipe: case Type::ObjCTypeParam: case Type::DeducedTemplateSpecialization: - emit_warning(c, decl, "missed a '%s' type", ty->getTypeClassName()); + emit_warning(c, decl->getLocation(), "missed a '%s' type", ty->getTypeClassName()); return c->codegen->builtin_types.entry_invalid; } zig_unreachable(); @@ -823,6 +821,8 @@ static AstNode * trans_implicit_cast_expr(Context *c, ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { case CK_LValueToRValue: return trans_expr(c, stmt->getSubExpr()); + case CK_IntegralCast: + zig_panic("TODO handle C translation cast CK_IntegralCast"); case CK_Dependent: zig_panic("TODO handle C translation cast CK_Dependent"); case CK_BitCast: @@ -871,8 +871,6 @@ static AstNode * trans_implicit_cast_expr(Context *c, ImplicitCastExpr *stmt) { zig_panic("TODO handle C translation cast CK_ToVoid"); case CK_VectorSplat: zig_panic("TODO handle C translation cast CK_VectorSplat"); - case CK_IntegralCast: - zig_panic("TODO handle C translation cast CK_IntegralCast"); case CK_IntegralToBoolean: zig_panic("TODO handle C translation cast CK_IntegralToBoolean"); case CK_IntegralToFloating: @@ -1424,7 +1422,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { TypeTableEntry *fn_type = resolve_qual_type(c, fn_decl->getType(), fn_decl); if (fn_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, fn_decl, "ignoring function '%s' - unable to resolve type", buf_ptr(fn_name)); + emit_warning(c, fn_decl->getLocation(), "ignoring function '%s' - unable to resolve type", buf_ptr(fn_name)); return; } assert(fn_type->id == TypeTableEntryIdFn); @@ -1482,7 +1480,7 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) TypeTableEntry *child_type = resolve_qual_type(c, child_qt, typedef_decl); if (child_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, typedef_decl, "typedef %s - unresolved child type", buf_ptr(type_name)); + emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); return; } add_const_type(c, type_name, child_type); @@ -1663,7 +1661,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ const char *raw_name = decl_name(record_decl); if (!record_decl->isStruct()) { - emit_warning(c, record_decl, "skipping record %s, not a struct", raw_name); + emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); return c->codegen->builtin_types.entry_invalid; } @@ -1702,7 +1700,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ const FieldDecl *field_decl = *it; if (field_decl->isBitField()) { - emit_warning(c, field_decl, "struct %s demoted to opaque type - has bitfield\n", buf_ptr(bare_name)); + emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield\n", buf_ptr(bare_name)); replace_with_fwd_decl(c, struct_type, full_type_name); return struct_type; } @@ -1729,7 +1727,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ type_struct_field->type_entry = field_type; if (type_is_invalid(field_type) || !type_is_complete(field_type)) { - emit_warning(c, field_decl, "struct %s demoted to opaque type - unresolved type\n", buf_ptr(bare_name)); + emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - unresolved type\n", buf_ptr(bare_name)); replace_with_fwd_decl(c, struct_type, full_type_name); return struct_type; } @@ -1810,17 +1808,17 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { case VarDecl::TLS_None: break; case VarDecl::TLS_Static: - emit_warning(c, var_decl, "ignoring variable '%s' - static thread local storage\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - static thread local storage\n", buf_ptr(name)); return; case VarDecl::TLS_Dynamic: - emit_warning(c, var_decl, "ignoring variable '%s' - dynamic thread local storage\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - dynamic thread local storage\n", buf_ptr(name)); return; } QualType qt = var_decl->getType(); TypeTableEntry *var_type = resolve_qual_type(c, qt, var_decl); if (var_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, var_decl, "ignoring variable '%s' - unresolved type\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type\n", buf_ptr(name)); return; } @@ -1830,12 +1828,12 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { if (is_static && !is_extern) { if (!var_decl->hasInit()) { - emit_warning(c, var_decl, "ignoring variable '%s' - no initializer\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - no initializer\n", buf_ptr(name)); return; } APValue *ap_value = var_decl->evaluateValue(); if (!ap_value) { - emit_warning(c, var_decl, "ignoring variable '%s' - unable to evaluate initializer\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unable to evaluate initializer\n", buf_ptr(name)); return; } ConstExprValue *init_value = nullptr; @@ -1843,7 +1841,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { case APValue::Int: { if (var_type->id != TypeTableEntryIdInt) { - emit_warning(c, var_decl, + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name)); return; } @@ -1864,7 +1862,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { case APValue::Union: case APValue::MemberPointer: case APValue::AddrLabelDiff: - emit_warning(c, var_decl, + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unrecognized initializer value kind\n", buf_ptr(name)); return; } @@ -1881,7 +1879,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { return; } - emit_warning(c, var_decl, "ignoring variable '%s' - non-extern, non-static variable\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - non-extern, non-static variable\n", buf_ptr(name)); return; } @@ -1905,7 +1903,7 @@ static bool decl_visitor(void *context, const Decl *decl) { visit_var_decl(c, static_cast(decl)); break; default: - emit_warning(c, decl, "ignoring %s decl\n", decl->getDeclKindName()); + emit_warning(c, decl->getLocation(), "ignoring %s decl\n", decl->getDeclKindName()); } return true; From 80d75cf3bf2a1ec72e1ca2e03c599a72261e9604 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Sep 2017 14:39:17 -0400 Subject: [PATCH 04/16] here, have trans_qual_type --- src/parseh.cpp | 182 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/src/parseh.cpp b/src/parseh.cpp index 52b75e1b1a..c6e5b13630 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -43,7 +43,10 @@ struct Context { ZigList *errors; bool warnings_on; VisibMod visib_mod; + HashMap global_type_table; + HashMap global_type_table2; + HashMap struct_type_table; HashMap enum_type_table; HashMap decl_table; @@ -666,6 +669,185 @@ static bool c_is_float(Context *c, QualType qt) { static AstNode * trans_stmt(Context *c, Stmt *stmt); +static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLocation &source_loc, + HashMap *type_table) +{ + switch (ty->getTypeClass()) { + case Type::Builtin: + { + const BuiltinType *builtin_ty = static_cast(ty); + switch (builtin_ty->getKind()) { + case BuiltinType::Void: + zig_panic("TODO void type"); + case BuiltinType::Bool: + zig_panic("TODO bool type"); + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + zig_panic("TODO u8 type"); + case BuiltinType::SChar: + zig_panic("TODO i8 type"); + case BuiltinType::UShort: + zig_panic("TODO c_ushort type"); + case BuiltinType::UInt: + zig_panic("TODO c_uint type"); + case BuiltinType::ULong: + zig_panic("TODO c_ulong type"); + case BuiltinType::ULongLong: + zig_panic("TODO c_ulonglong type"); + case BuiltinType::Short: + zig_panic("TODO c_short type"); + case BuiltinType::Int: + zig_panic("TODO c_int type"); + case BuiltinType::Long: + zig_panic("TODO c_long type"); + case BuiltinType::LongLong: + zig_panic("TODO c_longlong type"); + case BuiltinType::UInt128: + zig_panic("TODO u128 type"); + case BuiltinType::Int128: + zig_panic("TODO i128 type"); + case BuiltinType::Float: + zig_panic("TODO f32 type"); + case BuiltinType::Double: + zig_panic("TODO f64 type"); + case BuiltinType::Float128: + zig_panic("TODO f128 type"); + case BuiltinType::LongDouble: + zig_panic("TODO c_longdouble type"); + case BuiltinType::WChar_U: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::WChar_S: + case BuiltinType::Half: + case BuiltinType::NullPtr: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + case BuiltinType::OMPArraySection: + case BuiltinType::Dependent: + case BuiltinType::Overload: + case BuiltinType::BoundMember: + case BuiltinType::PseudoObject: + case BuiltinType::UnknownAny: + case BuiltinType::BuiltinFn: + case BuiltinType::ARCUnbridgedCast: + + case BuiltinType::OCLImage1dRO: + case BuiltinType::OCLImage1dArrayRO: + case BuiltinType::OCLImage1dBufferRO: + case BuiltinType::OCLImage2dRO: + case BuiltinType::OCLImage2dArrayRO: + case BuiltinType::OCLImage2dDepthRO: + case BuiltinType::OCLImage2dArrayDepthRO: + case BuiltinType::OCLImage2dMSAARO: + case BuiltinType::OCLImage2dArrayMSAARO: + case BuiltinType::OCLImage2dMSAADepthRO: + case BuiltinType::OCLImage2dArrayMSAADepthRO: + case BuiltinType::OCLImage3dRO: + case BuiltinType::OCLImage1dWO: + case BuiltinType::OCLImage1dArrayWO: + case BuiltinType::OCLImage1dBufferWO: + case BuiltinType::OCLImage2dWO: + case BuiltinType::OCLImage2dArrayWO: + case BuiltinType::OCLImage2dDepthWO: + case BuiltinType::OCLImage2dArrayDepthWO: + case BuiltinType::OCLImage2dMSAAWO: + case BuiltinType::OCLImage2dArrayMSAAWO: + case BuiltinType::OCLImage2dMSAADepthWO: + case BuiltinType::OCLImage2dArrayMSAADepthWO: + case BuiltinType::OCLImage3dWO: + case BuiltinType::OCLImage1dRW: + case BuiltinType::OCLImage1dArrayRW: + case BuiltinType::OCLImage1dBufferRW: + case BuiltinType::OCLImage2dRW: + case BuiltinType::OCLImage2dArrayRW: + case BuiltinType::OCLImage2dDepthRW: + case BuiltinType::OCLImage2dArrayDepthRW: + case BuiltinType::OCLImage2dMSAARW: + case BuiltinType::OCLImage2dArrayMSAARW: + case BuiltinType::OCLImage2dMSAADepthRW: + case BuiltinType::OCLImage2dArrayMSAADepthRW: + case BuiltinType::OCLImage3dRW: + case BuiltinType::OCLSampler: + case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLReserveID: + zig_panic("TODO more c type"); + } + break; + } + case Type::Pointer: + zig_panic("TODO pointer"); + case Type::Typedef: + zig_panic("TODO typedef"); + case Type::Elaborated: + zig_panic("TODO elaborated"); + case Type::FunctionProto: + zig_panic("TODO FunctionProto"); + case Type::Record: + zig_panic("TODO Record"); + case Type::Enum: + zig_panic("TODO Enum"); + case Type::ConstantArray: + zig_panic("TODO ConstantArray"); + case Type::Paren: + zig_panic("TODO Paren"); + case Type::Decayed: + zig_panic("TODO Decayed"); + case Type::Attributed: + zig_panic("TODO Attributed"); + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionNoProto: + case Type::UnresolvedUsing: + case Type::Adjusted: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::UnaryTransform: + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + case Type::TemplateSpecialization: + case Type::Auto: + case Type::InjectedClassName: + case Type::DependentName: + case Type::DependentTemplateSpecialization: + case Type::PackExpansion: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::Complex: + case Type::ObjCObjectPointer: + case Type::Atomic: + case Type::Pipe: + case Type::ObjCTypeParam: + case Type::DeducedTemplateSpecialization: + zig_panic("TODO more c type aoeu"); + } + zig_unreachable(); +} + +static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc, + HashMap *type_table) +{ + return trans_type_with_table(c, qt.getTypePtr(), source_loc, type_table); +} + +static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { + return trans_qual_type_with_table(c, qt, source_loc, &c->global_type_table2); +} + + static AstNode * trans_expr(Context *c, Expr *expr) { return trans_stmt(c, expr); } From 0d0fffe4d22169e5dae08e88c0fb6c1b56824c61 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Fri, 1 Sep 2017 11:39:48 -0700 Subject: [PATCH 05/16] start implementing variable declaration translation --- src/parseh.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 206 insertions(+), 32 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 52b75e1b1a..747a7fcaab 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -664,10 +664,10 @@ static bool c_is_float(Context *c, QualType qt) { } } -static AstNode * trans_stmt(Context *c, Stmt *stmt); +static AstNode * trans_stmt(Context *c, AstNode *block, Stmt *stmt); -static AstNode * trans_expr(Context *c, Expr *expr) { - return trans_stmt(c, expr); +static AstNode * trans_expr(Context *c, AstNode *block, Expr *expr) { + return trans_stmt(c, block, expr); } static AstNode * trans_create_node(Context *c, Stmt *stmt, NodeType id) { @@ -678,22 +678,23 @@ static AstNode * trans_create_node(Context *c, Stmt *stmt, NodeType id) { return node; } -static AstNode * trans_compound_stmt(Context *c, CompoundStmt *stmt) { - AstNode *block_node = trans_create_node(c, stmt, NodeTypeBlock); +static AstNode * trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { + AstNode *child_block = trans_create_node(c, stmt, NodeTypeBlock); for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { - AstNode *child_node = trans_stmt(c, *it); - block_node->data.block.statements.append(child_node); + AstNode *child_node = trans_stmt(c, child_block, *it); + if (child_node != nullptr) + child_block->data.block.statements.append(child_node); } - return block_node; + return child_block; } -static AstNode *trans_return_stmt(Context *c, ReturnStmt *stmt) { +static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) { Expr *value_expr = stmt->getRetValue(); if (value_expr == nullptr) { zig_panic("TODO handle C return void"); } else { AstNode *return_node = trans_create_node(c, stmt, NodeTypeReturnExpr); - return_node->data.return_expr.expr = trans_expr(c, value_expr); + return_node->data.return_expr.expr = trans_expr(c, block, value_expr); return return_node; } } @@ -726,21 +727,21 @@ static AstNode * trans_integer_literal(Context *c, IntegerLiteral *stmt) { return node; } -static AstNode * trans_conditional_operator(Context *c, ConditionalOperator *stmt) { +static AstNode * trans_conditional_operator(Context *c, AstNode *block, ConditionalOperator *stmt) { AstNode *node = trans_create_node(c, stmt, NodeTypeIfBoolExpr); Expr *cond_expr = stmt->getCond(); Expr *true_expr = stmt->getTrueExpr(); Expr *false_expr = stmt->getFalseExpr(); - node->data.if_bool_expr.condition = trans_expr(c, cond_expr); - node->data.if_bool_expr.then_block = trans_expr(c, true_expr); - node->data.if_bool_expr.else_node = trans_expr(c, false_expr); + node->data.if_bool_expr.condition = trans_expr(c, block, cond_expr); + node->data.if_bool_expr.then_block = trans_expr(c, block, true_expr); + node->data.if_bool_expr.else_node = trans_expr(c, block, false_expr); return node; } -static AstNode * trans_binary_operator(Context *c, BinaryOperator *stmt) { +static AstNode * trans_binary_operator(Context *c, AstNode *block, BinaryOperator *stmt) { switch (stmt->getOpcode()) { case BO_PtrMemD: zig_panic("TODO handle more C binary operators: BO_PtrMemD"); @@ -764,8 +765,8 @@ static AstNode * trans_binary_operator(Context *c, BinaryOperator *stmt) { { AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = BinOpTypeCmpLessThan; - node->data.bin_op_expr.op1 = trans_expr(c, stmt->getLHS()); - node->data.bin_op_expr.op2 = trans_expr(c, stmt->getRHS()); + node->data.bin_op_expr.op1 = trans_expr(c, block, stmt->getLHS()); + node->data.bin_op_expr.op2 = trans_expr(c, block, stmt->getRHS()); return node; } case BO_GT: @@ -817,10 +818,10 @@ static AstNode * trans_binary_operator(Context *c, BinaryOperator *stmt) { zig_unreachable(); } -static AstNode * trans_implicit_cast_expr(Context *c, ImplicitCastExpr *stmt) { +static AstNode * trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { case CK_LValueToRValue: - return trans_expr(c, stmt->getSubExpr()); + return trans_expr(c, block, stmt->getSubExpr()); case CK_IntegralCast: zig_panic("TODO handle C translation cast CK_IntegralCast"); case CK_Dependent: @@ -955,7 +956,7 @@ static AstNode * trans_create_num_lit_node_unsigned(Context *c, Stmt *stmt, uint return node; } -static AstNode * trans_unary_operator(Context *c, UnaryOperator *stmt) { +static AstNode * trans_unary_operator(Context *c, AstNode *block, UnaryOperator *stmt) { switch (stmt->getOpcode()) { case UO_PostInc: zig_panic("TODO handle C translation UO_PostInc"); @@ -977,13 +978,13 @@ static AstNode * trans_unary_operator(Context *c, UnaryOperator *stmt) { if (c_is_signed_integer(c, op_expr->getType()) || c_is_float(c, op_expr->getType())) { AstNode *node = trans_create_node(c, stmt, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = PrefixOpNegation; - node->data.prefix_op_expr.primary_expr = trans_expr(c, op_expr); + node->data.prefix_op_expr.primary_expr = trans_expr(c, block, op_expr); return node; } else if (c_is_unsigned_integer(c, op_expr->getType())) { // we gotta emit 0 -% x AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); node->data.bin_op_expr.op1 = trans_create_num_lit_node_unsigned(c, stmt, 0); - node->data.bin_op_expr.op2 = trans_expr(c, op_expr); + node->data.bin_op_expr.op2 = trans_expr(c, block, op_expr); node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; return node; } else { @@ -1006,25 +1007,200 @@ static AstNode * trans_unary_operator(Context *c, UnaryOperator *stmt) { zig_unreachable(); } -static AstNode *trans_stmt(Context *c, Stmt *stmt) { +static AstNode * trans_local_declaration(Context *c, AstNode *block, DeclStmt *stmt) { + for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { + Decl *decl = *iter; + switch (decl->getKind()) { + case Decl::Var: { + VarDecl *var_decl = (VarDecl *)decl; + AstNode *node = trans_create_node(c, stmt, NodeTypeVariableDeclaration); + node->data.variable_declaration.symbol = buf_create_from_str(decl_name(var_decl)); + QualType qual_type = var_decl->getTypeSourceInfo()->getType(); + node->data.variable_declaration.is_const = qual_type.isConstQualified(); + node->data.variable_declaration.type = trans_qual_type(c, block, qual_type); + if (var_decl->hasInit()) { + node->data.variable_declaration.expr = trans_expr(c, block, var_decl->getInit()); + } + + //emit_warning(c, decl->getLocation(), "asdf"); + + block->data.block.statements.append(node); + continue; + } + + case Decl::AccessSpec: + zig_panic("TODO handle decl kind AccessSpec"); + case Decl::Block: + zig_panic("TODO handle decl kind Block"); + case Decl::Captured: + zig_panic("TODO handle decl kind Captured"); + case Decl::ClassScopeFunctionSpecialization: + zig_panic("TODO handle decl kind ClassScopeFunctionSpecialization"); + case Decl::Empty: + zig_panic("TODO handle decl kind Empty"); + case Decl::Export: + zig_panic("TODO handle decl kind Export"); + case Decl::ExternCContext: + zig_panic("TODO handle decl kind ExternCContext"); + case Decl::FileScopeAsm: + zig_panic("TODO handle decl kind FileScopeAsm"); + case Decl::Friend: + zig_panic("TODO handle decl kind Friend"); + case Decl::FriendTemplate: + zig_panic("TODO handle decl kind FriendTemplate"); + case Decl::Import: + zig_panic("TODO handle decl kind Import"); + case Decl::LinkageSpec: + zig_panic("TODO handle decl kind LinkageSpec"); + case Decl::Label: + zig_panic("TODO handle decl kind Label"); + case Decl::Namespace: + zig_panic("TODO handle decl kind Namespace"); + case Decl::NamespaceAlias: + zig_panic("TODO handle decl kind NamespaceAlias"); + case Decl::ObjCCompatibleAlias: + zig_panic("TODO handle decl kind ObjCCompatibleAlias"); + case Decl::ObjCCategory: + zig_panic("TODO handle decl kind ObjCCategory"); + case Decl::ObjCCategoryImpl: + zig_panic("TODO handle decl kind ObjCCategoryImpl"); + case Decl::ObjCImplementation: + zig_panic("TODO handle decl kind ObjCImplementation"); + case Decl::ObjCInterface: + zig_panic("TODO handle decl kind ObjCInterface"); + case Decl::ObjCProtocol: + zig_panic("TODO handle decl kind ObjCProtocol"); + case Decl::ObjCMethod: + zig_panic("TODO handle decl kind ObjCMethod"); + case Decl::ObjCProperty: + zig_panic("TODO handle decl kind ObjCProperty"); + case Decl::BuiltinTemplate: + zig_panic("TODO handle decl kind BuiltinTemplate"); + case Decl::ClassTemplate: + zig_panic("TODO handle decl kind ClassTemplate"); + case Decl::FunctionTemplate: + zig_panic("TODO handle decl kind FunctionTemplate"); + case Decl::TypeAliasTemplate: + zig_panic("TODO handle decl kind TypeAliasTemplate"); + case Decl::VarTemplate: + zig_panic("TODO handle decl kind VarTemplate"); + case Decl::TemplateTemplateParm: + zig_panic("TODO handle decl kind TemplateTemplateParm"); + case Decl::Enum: + zig_panic("TODO handle decl kind Enum"); + case Decl::Record: + zig_panic("TODO handle decl kind Record"); + case Decl::CXXRecord: + zig_panic("TODO handle decl kind CXXRecord"); + case Decl::ClassTemplateSpecialization: + zig_panic("TODO handle decl kind ClassTemplateSpecialization"); + case Decl::ClassTemplatePartialSpecialization: + zig_panic("TODO handle decl kind ClassTemplatePartialSpecialization"); + case Decl::TemplateTypeParm: + zig_panic("TODO handle decl kind TemplateTypeParm"); + case Decl::ObjCTypeParam: + zig_panic("TODO handle decl kind ObjCTypeParam"); + case Decl::TypeAlias: + zig_panic("TODO handle decl kind TypeAlias"); + case Decl::Typedef: + zig_panic("TODO handle decl kind Typedef"); + case Decl::UnresolvedUsingTypename: + zig_panic("TODO handle decl kind UnresolvedUsingTypename"); + case Decl::Using: + zig_panic("TODO handle decl kind Using"); + case Decl::UsingDirective: + zig_panic("TODO handle decl kind UsingDirective"); + case Decl::UsingPack: + zig_panic("TODO handle decl kind UsingPack"); + case Decl::UsingShadow: + zig_panic("TODO handle decl kind UsingShadow"); + case Decl::ConstructorUsingShadow: + zig_panic("TODO handle decl kind ConstructorUsingShadow"); + case Decl::Binding: + zig_panic("TODO handle decl kind Binding"); + case Decl::Field: + zig_panic("TODO handle decl kind Field"); + case Decl::ObjCAtDefsField: + zig_panic("TODO handle decl kind ObjCAtDefsField"); + case Decl::ObjCIvar: + zig_panic("TODO handle decl kind ObjCIvar"); + case Decl::Function: + zig_panic("TODO handle decl kind Function"); + case Decl::CXXDeductionGuide: + zig_panic("TODO handle decl kind CXXDeductionGuide"); + case Decl::CXXMethod: + zig_panic("TODO handle decl kind CXXMethod"); + case Decl::CXXConstructor: + zig_panic("TODO handle decl kind CXXConstructor"); + case Decl::CXXConversion: + zig_panic("TODO handle decl kind CXXConversion"); + case Decl::CXXDestructor: + zig_panic("TODO handle decl kind CXXDestructor"); + case Decl::MSProperty: + zig_panic("TODO handle decl kind MSProperty"); + case Decl::NonTypeTemplateParm: + zig_panic("TODO handle decl kind NonTypeTemplateParm"); + case Decl::Decomposition: + zig_panic("TODO handle decl kind Decomposition"); + case Decl::ImplicitParam: + zig_panic("TODO handle decl kind ImplicitParam"); + case Decl::OMPCapturedExpr: + zig_panic("TODO handle decl kind OMPCapturedExpr"); + case Decl::ParmVar: + zig_panic("TODO handle decl kind ParmVar"); + case Decl::VarTemplateSpecialization: + zig_panic("TODO handle decl kind VarTemplateSpecialization"); + case Decl::VarTemplatePartialSpecialization: + zig_panic("TODO handle decl kind VarTemplatePartialSpecialization"); + case Decl::EnumConstant: + zig_panic("TODO handle decl kind EnumConstant"); + case Decl::IndirectField: + zig_panic("TODO handle decl kind IndirectField"); + case Decl::OMPDeclareReduction: + zig_panic("TODO handle decl kind OMPDeclareReduction"); + case Decl::UnresolvedUsingValue: + zig_panic("TODO handle decl kind UnresolvedUsingValue"); + case Decl::OMPThreadPrivate: + zig_panic("TODO handle decl kind OMPThreadPrivate"); + case Decl::ObjCPropertyImpl: + zig_panic("TODO handle decl kind ObjCPropertyImpl"); + case Decl::PragmaComment: + zig_panic("TODO handle decl kind PragmaComment"); + case Decl::PragmaDetectMismatch: + zig_panic("TODO handle decl kind PragmaDetectMismatch"); + case Decl::StaticAssert: + zig_panic("TODO handle decl kind StaticAssert"); + case Decl::TranslationUnit: + zig_panic("TODO handle decl kind TranslationUnit"); + } + zig_unreachable(); + } + + // declarations were already added + return nullptr; +} + +static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { case Stmt::ReturnStmtClass: - return trans_return_stmt(c, (ReturnStmt *)stmt); + return trans_return_stmt(c, block, (ReturnStmt *)stmt); case Stmt::CompoundStmtClass: - return trans_compound_stmt(c, (CompoundStmt *)stmt); + return trans_compound_stmt(c, block, (CompoundStmt *)stmt); case Stmt::IntegerLiteralClass: return trans_integer_literal(c, (IntegerLiteral *)stmt); case Stmt::ConditionalOperatorClass: - return trans_conditional_operator(c, (ConditionalOperator *)stmt); + return trans_conditional_operator(c, block, (ConditionalOperator *)stmt); case Stmt::BinaryOperatorClass: - return trans_binary_operator(c, (BinaryOperator *)stmt); + return trans_binary_operator(c, block, (BinaryOperator *)stmt); case Stmt::ImplicitCastExprClass: - return trans_implicit_cast_expr(c, (ImplicitCastExpr *)stmt); + return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); case Stmt::DeclRefExprClass: return trans_decl_ref_expr(c, (DeclRefExpr *)stmt); case Stmt::UnaryOperatorClass: - return trans_unary_operator(c, (UnaryOperator *)stmt); + return trans_unary_operator(c, block, (UnaryOperator *)stmt); + case Stmt::DeclStmtClass: + return trans_local_declaration(c, block, (DeclStmt *)stmt); case Stmt::CaseStmtClass: zig_panic("TODO handle C CaseStmtClass"); case Stmt::DefaultStmtClass: @@ -1057,8 +1233,6 @@ static AstNode *trans_stmt(Context *c, Stmt *stmt) { 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: @@ -1409,7 +1583,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { if (fn_decl->hasBody()) { fprintf(stderr, "fn %s\n", buf_ptr(fn_name)); Stmt *body = fn_decl->getBody(); - AstNode *body_node = trans_stmt(c, body); + AstNode *body_node = trans_stmt(c, nullptr, body); ast_render(c->codegen, stderr, body_node, 4); fprintf(stderr, "\n"); } From 7e1bf6d29b8c644096058a9444614b65055ee9df Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Fri, 1 Sep 2017 11:45:06 -0700 Subject: [PATCH 06/16] progress toward variable declaration translation --- src/parseh.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index a79989b92d..154dddf329 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -1198,13 +1198,11 @@ static AstNode * trans_local_declaration(Context *c, AstNode *block, DeclStmt *s node->data.variable_declaration.symbol = buf_create_from_str(decl_name(var_decl)); QualType qual_type = var_decl->getTypeSourceInfo()->getType(); node->data.variable_declaration.is_const = qual_type.isConstQualified(); - node->data.variable_declaration.type = trans_qual_type(c, block, qual_type); + node->data.variable_declaration.type = trans_qual_type(c, qual_type, stmt->getStartLoc()); if (var_decl->hasInit()) { node->data.variable_declaration.expr = trans_expr(c, block, var_decl->getInit()); } - //emit_warning(c, decl->getLocation(), "asdf"); - block->data.block.statements.append(node); continue; } From fa8912ab7853501b5cbae57dbc34ba8d2ac0e123 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Fri, 1 Sep 2017 12:03:21 -0700 Subject: [PATCH 07/16] translate some variable declaration cases --- src/parseh.cpp | 87 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 154dddf329..f80c1a59e9 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -668,11 +668,19 @@ static bool c_is_float(Context *c, QualType qt) { } static AstNode * trans_stmt(Context *c, AstNode *block, Stmt *stmt); +static AstNode * trans_create_node(Context *c, NodeType id); +static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); static AstNode * trans_expr(Context *c, AstNode *block, Expr *expr) { return trans_stmt(c, block, expr); } +static AstNode *trans_create_symbol_node(Context *c, const char * name) { + AstNode *node = trans_create_node(c, NodeTypeSymbol); + node->data.symbol_expr.symbol = buf_create_from_str(name); + return node; +} + static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLocation &source_loc, HashMap *type_table) { @@ -682,43 +690,43 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo const BuiltinType *builtin_ty = static_cast(ty); switch (builtin_ty->getKind()) { case BuiltinType::Void: - zig_panic("TODO void type"); + return trans_create_symbol_node(c, "c_void"); case BuiltinType::Bool: - zig_panic("TODO bool type"); + return trans_create_symbol_node(c, "bool"); case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: - zig_panic("TODO u8 type"); + return trans_create_symbol_node(c, "u8"); case BuiltinType::SChar: - zig_panic("TODO i8 type"); + return trans_create_symbol_node(c, "i8"); case BuiltinType::UShort: - zig_panic("TODO c_ushort type"); + return trans_create_symbol_node(c, "c_ushort"); case BuiltinType::UInt: - zig_panic("TODO c_uint type"); + return trans_create_symbol_node(c, "c_uint"); case BuiltinType::ULong: - zig_panic("TODO c_ulong type"); + return trans_create_symbol_node(c, "c_ulong"); case BuiltinType::ULongLong: - zig_panic("TODO c_ulonglong type"); + return trans_create_symbol_node(c, "c_ulonglong"); case BuiltinType::Short: - zig_panic("TODO c_short type"); + return trans_create_symbol_node(c, "c_short"); case BuiltinType::Int: - zig_panic("TODO c_int type"); + return trans_create_symbol_node(c, "c_int"); case BuiltinType::Long: - zig_panic("TODO c_long type"); + return trans_create_symbol_node(c, "c_long"); case BuiltinType::LongLong: - zig_panic("TODO c_longlong type"); + return trans_create_symbol_node(c, "c_longlong"); case BuiltinType::UInt128: - zig_panic("TODO u128 type"); + return trans_create_symbol_node(c, "u128"); case BuiltinType::Int128: - zig_panic("TODO i128 type"); + return trans_create_symbol_node(c, "i128"); case BuiltinType::Float: - zig_panic("TODO f32 type"); + return trans_create_symbol_node(c, "f32"); case BuiltinType::Double: - zig_panic("TODO f64 type"); + return trans_create_symbol_node(c, "f64"); case BuiltinType::Float128: - zig_panic("TODO f128 type"); + return trans_create_symbol_node(c, "f128"); case BuiltinType::LongDouble: - zig_panic("TODO c_longdouble type"); + return trans_create_symbol_node(c, "c_longdouble"); case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: @@ -783,7 +791,26 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo break; } case Type::Pointer: - zig_panic("TODO pointer"); + { + const PointerType *pointer_ty = static_cast(ty); + QualType child_qt = pointer_ty->getPointeeType(); + AstNode *child_node = trans_qual_type(c, child_qt, source_loc); + if (child_node == nullptr) return nullptr; + + if (qual_type_child_is_fn_proto(child_qt)) { + zig_panic("TODO pointer to function proto"); + } + + AstNode *pointer_node = trans_create_node(c, NodeTypeAddrOfExpr); + pointer_node->data.addr_of_expr.is_const = child_qt.isConstQualified(); + pointer_node->data.addr_of_expr.is_volatile = child_qt.isVolatileQualified(); + pointer_node->data.addr_of_expr.op_expr = child_node; + + AstNode *maybe_node = trans_create_node(c, NodeTypePrefixOpExpr); + maybe_node->data.prefix_op_expr.prefix_op = PrefixOpMaybe; + maybe_node->data.prefix_op_expr.primary_expr = pointer_node; + return maybe_node; + } case Type::Typedef: zig_panic("TODO typedef"); case Type::Elaborated: @@ -851,7 +878,7 @@ static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation & return trans_qual_type_with_table(c, qt, source_loc, &c->global_type_table2); } -static AstNode * trans_create_node(Context *c, Stmt *stmt, NodeType id) { +static AstNode * trans_create_node(Context *c, NodeType id) { AstNode *node = allocate(1); node->type = id; node->owner = c->import; @@ -860,7 +887,7 @@ static AstNode * trans_create_node(Context *c, Stmt *stmt, NodeType id) { } static AstNode * trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { - AstNode *child_block = trans_create_node(c, stmt, NodeTypeBlock); + AstNode *child_block = trans_create_node(c, NodeTypeBlock); for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { AstNode *child_node = trans_stmt(c, child_block, *it); if (child_node != nullptr) @@ -874,7 +901,7 @@ static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) if (value_expr == nullptr) { zig_panic("TODO handle C return void"); } else { - AstNode *return_node = trans_create_node(c, stmt, NodeTypeReturnExpr); + AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); return_node->data.return_expr.expr = trans_expr(c, block, value_expr); return return_node; } @@ -898,7 +925,7 @@ static void aps_int_to_bigint(Context *c, const llvm::APSInt &aps_int, BigInt *b } static AstNode * trans_integer_literal(Context *c, IntegerLiteral *stmt) { - AstNode *node = trans_create_node(c, stmt, NodeTypeIntLiteral); + AstNode *node = trans_create_node(c, NodeTypeIntLiteral); llvm::APSInt result; if (!stmt->EvaluateAsInt(result, *c->ctx)) { fprintf(stderr, "TODO unable to convert integer literal to zig\n"); @@ -909,7 +936,7 @@ static AstNode * trans_integer_literal(Context *c, IntegerLiteral *stmt) { } static AstNode * trans_conditional_operator(Context *c, AstNode *block, ConditionalOperator *stmt) { - AstNode *node = trans_create_node(c, stmt, NodeTypeIfBoolExpr); + AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); Expr *cond_expr = stmt->getCond(); Expr *true_expr = stmt->getTrueExpr(); @@ -944,7 +971,7 @@ static AstNode * trans_binary_operator(Context *c, AstNode *block, BinaryOperato zig_panic("TODO handle more C binary operators: BO_Shr"); case BO_LT: { - AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); + AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = BinOpTypeCmpLessThan; node->data.bin_op_expr.op1 = trans_expr(c, block, stmt->getLHS()); node->data.bin_op_expr.op2 = trans_expr(c, block, stmt->getRHS()); @@ -1125,13 +1152,13 @@ static AstNode * trans_decl_ref_expr(Context *c, DeclRefExpr *stmt) { ValueDecl *value_decl = stmt->getDecl(); const char *name = decl_name(value_decl); - AstNode *node = trans_create_node(c, stmt, NodeTypeSymbol); + AstNode *node = trans_create_node(c, NodeTypeSymbol); node->data.symbol_expr.symbol = buf_create_from_str(name); return node; } static AstNode * trans_create_num_lit_node_unsigned(Context *c, Stmt *stmt, uint64_t x) { - AstNode *node = trans_create_node(c, stmt, NodeTypeIntLiteral); + AstNode *node = trans_create_node(c, NodeTypeIntLiteral); node->data.int_literal.bigint = allocate(1); bigint_init_unsigned(node->data.int_literal.bigint, x); return node; @@ -1157,13 +1184,13 @@ static AstNode * trans_unary_operator(Context *c, AstNode *block, UnaryOperator { Expr *op_expr = stmt->getSubExpr(); if (c_is_signed_integer(c, op_expr->getType()) || c_is_float(c, op_expr->getType())) { - AstNode *node = trans_create_node(c, stmt, NodeTypePrefixOpExpr); + AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = PrefixOpNegation; node->data.prefix_op_expr.primary_expr = trans_expr(c, block, op_expr); return node; } else if (c_is_unsigned_integer(c, op_expr->getType())) { // we gotta emit 0 -% x - AstNode *node = trans_create_node(c, stmt, NodeTypeBinOpExpr); + AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.op1 = trans_create_num_lit_node_unsigned(c, stmt, 0); node->data.bin_op_expr.op2 = trans_expr(c, block, op_expr); node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; @@ -1194,7 +1221,7 @@ static AstNode * trans_local_declaration(Context *c, AstNode *block, DeclStmt *s switch (decl->getKind()) { case Decl::Var: { VarDecl *var_decl = (VarDecl *)decl; - AstNode *node = trans_create_node(c, stmt, NodeTypeVariableDeclaration); + AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); node->data.variable_declaration.symbol = buf_create_from_str(decl_name(var_decl)); QualType qual_type = var_decl->getTypeSourceInfo()->getType(); node->data.variable_declaration.is_const = qual_type.isConstQualified(); From 0f38955ee5b5ff2251fdbc3ac4d95a9aecfdfd3c Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Fri, 1 Sep 2017 12:51:45 -0700 Subject: [PATCH 08/16] translate while loops and implicit bitcasts --- src/parseh.cpp | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index f80c1a59e9..d087322a78 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -949,6 +949,14 @@ static AstNode * trans_conditional_operator(Context *c, AstNode *block, Conditio return node; } +static AstNode * trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) { + AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); + node->data.bin_op_expr.bin_op = bin_op; + node->data.bin_op_expr.op1 = trans_expr(c, block, lhs); + node->data.bin_op_expr.op2 = trans_expr(c, block, rhs); + return node; +} + static AstNode * trans_binary_operator(Context *c, AstNode *block, BinaryOperator *stmt) { switch (stmt->getOpcode()) { case BO_PtrMemD: @@ -970,19 +978,13 @@ static AstNode * trans_binary_operator(Context *c, AstNode *block, BinaryOperato case BO_Shr: zig_panic("TODO handle more C binary operators: BO_Shr"); case BO_LT: - { - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.bin_op = BinOpTypeCmpLessThan; - node->data.bin_op_expr.op1 = trans_expr(c, block, stmt->getLHS()); - node->data.bin_op_expr.op2 = trans_expr(c, block, stmt->getRHS()); - return node; - } + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); case BO_GT: - zig_panic("TODO handle more C binary operators: BO_GT"); + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); case BO_LE: - zig_panic("TODO handle more C binary operators: BO_LE"); + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); case BO_GE: - zig_panic("TODO handle more C binary operators: BO_GE"); + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); case BO_EQ: zig_panic("TODO handle more C binary operators: BO_EQ"); case BO_NE: @@ -1031,7 +1033,14 @@ static AstNode * trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCa case CK_LValueToRValue: return trans_expr(c, block, stmt->getSubExpr()); case CK_IntegralCast: - zig_panic("TODO handle C translation cast CK_IntegralCast"); + { + AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); + node->data.fn_call_expr.fn_ref_expr = trans_create_symbol_node(c, "bitCast"); + node->data.fn_call_expr.is_builtin = true; + node->data.fn_call_expr.params.append(trans_qual_type(c, stmt->getType(), stmt->getExprLoc())); + node->data.fn_call_expr.params.append(trans_expr(c, block, stmt->getSubExpr())); + return node; + } case CK_Dependent: zig_panic("TODO handle C translation cast CK_Dependent"); case CK_BitCast: @@ -1386,6 +1395,13 @@ static AstNode * trans_local_declaration(Context *c, AstNode *block, DeclStmt *s return nullptr; } +static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { + AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); + while_node->data.while_expr.condition = trans_expr(c, block, stmt->getCond()); + while_node->data.while_expr.body = trans_stmt(c, block, stmt->getBody()); + return while_node; +} + static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1407,14 +1423,14 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { return trans_unary_operator(c, block, (UnaryOperator *)stmt); case Stmt::DeclStmtClass: return trans_local_declaration(c, block, (DeclStmt *)stmt); + case Stmt::WhileStmtClass: + return trans_while_loop(c, block, (WhileStmt *)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: From e1d5da20a5d5e54b9dba6031c97fe232192e69cd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 2 Sep 2017 04:11:23 -0400 Subject: [PATCH 09/16] rewrite parseh to use AST instead of direct types some tests still failing --- src/all_types.hpp | 1 + src/ast_render.cpp | 178 +---- src/ast_render.hpp | 2 - src/bigint.cpp | 19 + src/bigint.hpp | 1 + src/codegen.hpp | 1 - src/ir.cpp | 77 +-- src/ir.hpp | 2 - src/main.cpp | 2 +- src/parseh.cpp | 1629 ++++++++++++++++++-------------------------- test/parseh.zig | 18 +- 11 files changed, 744 insertions(+), 1186 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index e785e61c1b..a4e86c6b20 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -751,6 +751,7 @@ struct AstNodeContainerDecl { ZigList fields; ZigList decls; ContainerLayout layout; + AstNode *init_arg_expr; // enum(T) or struct(endianness) }; struct AstNodeStructField { diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 74dbab657c..8df4dc0436 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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 " : ""; @@ -439,8 +439,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 +653,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 +994,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(¶m_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; - } - } -} - - diff --git a/src/ast_render.hpp b/src/ast_render.hpp index 555ce77c7a..d37002d8c7 100644 --- a/src/ast_render.hpp +++ b/src/ast_render.hpp @@ -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 diff --git a/src/bigint.cpp b/src/bigint.cpp index 63393f6358..395d9fce80 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -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(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); diff --git a/src/bigint.hpp b/src/bigint.hpp index eeb70a4d35..c77fb52245 100644 --- a/src/bigint.hpp +++ b/src/bigint.hpp @@ -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); diff --git a/src/codegen.hpp b/src/codegen.hpp index 74f3be1658..4947d1a4dc 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -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 diff --git a/src/ir.cpp b/src/ir.cpp index 74a48f6f50..4049295815 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6114,9 +6114,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_void(irb, parent_scope, node); + } 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 +13363,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; @@ -15515,65 +15522,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(arg_count); - VariableTableEntry **arg_vars = allocate(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; -} - diff --git a/src/ir.hpp b/src/ir.hpp index 4a9de7e574..d8dfc3dcfa 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -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 diff --git a/src/main.cpp b/src/main.cpp index a31c15b868..f4fc581046 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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; diff --git a/src/parseh.cpp b/src/parseh.cpp index d087322a78..e466e5bb73 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -15,6 +15,7 @@ #include "parseh.hpp" #include "parser.hpp" + #include #include #include @@ -28,14 +29,9 @@ struct MacroSymbol { Buf *value; }; -struct GlobalValue { - TypeTableEntry *type; - bool is_const; -}; - struct Alias { Buf *name; - Tld *tld; + AstNode *node; }; struct Context { @@ -43,30 +39,26 @@ struct Context { ZigList *errors; bool warnings_on; VisibMod visib_mod; - - HashMap global_type_table; - HashMap global_type_table2; - - HashMap struct_type_table; - HashMap enum_type_table; - HashMap decl_table; - HashMap macro_table; + AstNode *root; + HashMap global_type_table; + HashMap struct_type_table; + HashMap enum_type_table; + HashMap decl_table; + HashMap macro_table; SourceManager *source_manager; ZigList aliases; ZigList macro_symbols; AstNode *source_node; - uint32_t next_anon_index; CodeGen *codegen; ASTContext *ctx; }; -static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl, - HashMap *type_table); - -static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl); -static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl); -static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); +static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); +static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); +static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc, + HashMap *type_table); +static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); __attribute__ ((format (printf, 3, 4))) @@ -93,31 +85,180 @@ static void emit_warning(Context *c, const SourceLocation &sl, const char *forma fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); } -static uint32_t get_next_anon_index(Context *c) { - uint32_t result = c->next_anon_index; - c->next_anon_index += 1; - return result; -} - -static void add_global_alias(Context *c, Buf *name, Tld *tld) { - c->import->decls_scope->decl_table.put(name, tld); -} - -static void add_global_weak_alias(Context *c, Buf *name, Tld *tld) { +static void add_global_weak_alias(Context *c, Buf *name, AstNode *node) { Alias *alias = c->aliases.add_one(); alias->name = name; - alias->tld = tld; + alias->node = node; } -static void add_global(Context *c, Tld *tld) { - return add_global_alias(c, tld->name, tld); +static AstNode * trans_create_node(Context *c, NodeType id) { + AstNode *node = allocate(1); + node->type = id; + node->owner = c->import; + // TODO line/column. mapping to C file?? + return node; } -static Tld *get_global(Context *c, Buf *name) { - { - auto entry = c->import->decls_scope->decl_table.maybe_get(name); - if (entry) - return entry->value; +static AstNode *trans_create_node_float_lit(Context *c, double value) { + AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); + node->data.float_literal.bigfloat = allocate(1); + bigfloat_init_64(node->data.float_literal.bigfloat, value); + return node; +} + +static AstNode *trans_create_node_symbol(Context *c, Buf *name) { + AstNode *node = trans_create_node(c, NodeTypeSymbol); + node->data.symbol_expr.symbol = name; + return node; +} + +static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { + return trans_create_node_symbol(c, buf_create_from_str(name)); +} + +static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { + AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); + node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); + node->data.fn_call_expr.is_builtin = true; + return node; +} + +static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { + return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); +} + +static AstNode *trans_create_node_opaque(Context *c) { + return trans_create_node_builtin_fn_call_str(c, "opaque"); +} + +static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { + AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); + node->data.field_access_expr.struct_expr = container; + node->data.field_access_expr.field_name = field_name; + return node; +} + +static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { + AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); + node->data.prefix_op_expr.prefix_op = op; + node->data.prefix_op_expr.primary_expr = child_node; + return node; +} + +static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { + AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); + node->data.addr_of_expr.is_const = is_const; + node->data.addr_of_expr.is_volatile = is_volatile; + node->data.addr_of_expr.op_expr = child_node; + return node; +} + +static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { + AstNode *node = trans_create_node(c, NodeTypeStringLiteral); + node->data.string_literal.buf = buf; + node->data.string_literal.c = true; + return node; +} + +static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { + AstNode *node = trans_create_node(c, NodeTypeIntLiteral); + node->data.int_literal.bigint = allocate(1); + bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); + return node; +} + +static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { + return trans_create_node_unsigned_negative(c, x, false); +} + +static AstNode *trans_create_node_cast(Context *c, AstNode *dest, AstNode *src) { + AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); + node->data.fn_call_expr.fn_ref_expr = dest; + node->data.fn_call_expr.params.resize(1); + node->data.fn_call_expr.params.items[0] = src; + return node; +} + +static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, + const char *type_name) +{ + AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); + return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); +} + +static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { + AstNode *node = trans_create_node(c, NodeTypeArrayType); + node->data.array_type.size = size_node; + node->data.array_type.child_type = child_type_node; + return node; +} + +static AstNode *trans_create_node_var_decl(Context *c, bool is_const, Buf *var_name, AstNode *type_node, + AstNode *init_node) +{ + AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); + node->data.variable_declaration.visib_mod = c->visib_mod; + node->data.variable_declaration.symbol = var_name; + node->data.variable_declaration.is_const = is_const; + node->data.variable_declaration.type = type_node; + node->data.variable_declaration.expr = init_node; + return node; +} + + +static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { + AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); + AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); + fn_proto->data.fn_proto.visib_mod = c->visib_mod;; + fn_proto->data.fn_proto.name = fn_name; + fn_proto->data.fn_proto.is_inline = true; + fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? + + fn_def->data.fn_def.fn_proto = fn_proto; + fn_proto->data.fn_proto.fn_def_node = fn_def; + + AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name)); + AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); + fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; + + for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { + AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); + Buf *param_name = src_param_node->data.param_decl.name; + + AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); + dest_param_node->data.param_decl.name = param_name; + dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; + dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; + fn_proto->data.fn_proto.params.append(dest_param_node); + + fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); + + } + + AstNode *block = trans_create_node(c, NodeTypeBlock); + block->data.block.statements.resize(1); + block->data.block.statements.items[0] = fn_call_node; + + fn_def->data.fn_def.body = block; + return fn_def; +} + +static AstNode *get_global(Context *c, Buf *name) { + for (size_t i = 0; i < c->root->data.root.top_level_decls.length; i += 1) { + AstNode *decl_node = c->root->data.root.top_level_decls.items[i]; + if (decl_node->type == NodeTypeVariableDeclaration) { + if (buf_eql_buf(decl_node->data.variable_declaration.symbol, name)) { + return decl_node; + } + } else if (decl_node->type == NodeTypeFnDef) { + if (buf_eql_buf(decl_node->data.fn_def.fn_proto->data.fn_proto.name, name)) { + return decl_node; + } + } else if (decl_node->type == NodeTypeFnProto) { + if (buf_eql_buf(decl_node->data.fn_proto.name, name)) { + return decl_node; + } + } } { auto entry = c->macro_table.maybe_get(name); @@ -127,107 +268,29 @@ static Tld *get_global(Context *c, Buf *name) { return nullptr; } +static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { + bool is_const = true; + AstNode *type_node = nullptr; + AstNode *node = trans_create_node_var_decl(c, is_const, var_name, type_node, value_node); + c->root->data.root.top_level_decls.append(node); + return node; +} + static const char *decl_name(const Decl *decl) { const NamedDecl *named_decl = static_cast(decl); return (const char *)named_decl->getName().bytes_begin(); } -static void parseh_init_tld(Context *c, Tld *tld, TldId id, Buf *name) { - init_tld(tld, id, name, c->visib_mod, c->source_node, &c->import->decls_scope->base); - tld->resolution = TldResolutionOk; - tld->import = c->import; +static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { + AstNode *node = trans_create_node(c, NodeTypeIntLiteral); + node->data.int_literal.bigint = allocate(1); + bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), aps_int.isNegative()); + return node; + } -static Tld *create_inline_fn_tld(Context *c, Buf *fn_name, TldVar *tld_var) { - TldFn *tld_fn = allocate(1); - parseh_init_tld(c, &tld_fn->base, TldIdFn, fn_name); - tld_fn->fn_entry = ir_create_inline_fn(c->codegen, fn_name, tld_var->var, &c->import->decls_scope->base); - return &tld_fn->base; -} - -static TldVar *create_global_var(Context *c, Buf *name, ConstExprValue *var_value, bool is_const) { - auto entry = c->import->decls_scope->decl_table.maybe_get(name); - if (entry) { - Tld *existing_tld = entry->value; - assert(existing_tld->id == TldIdVar); - return (TldVar *)existing_tld; - } - TldVar *tld_var = allocate(1); - parseh_init_tld(c, &tld_var->base, TldIdVar, name); - tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, - name, is_const, var_value, &tld_var->base); - c->codegen->global_vars.append(tld_var); - return tld_var; -} - -static Tld *create_global_str_lit_var(Context *c, Buf *name, Buf *value) { - TldVar *tld_var = create_global_var(c, name, create_const_c_str_lit(c->codegen, value), true); - return &tld_var->base; -} - -static Tld *create_global_num_lit_unsigned_negative_type(Context *c, Buf *name, uint64_t x, bool negative, TypeTableEntry *type_entry) { - ConstExprValue *var_val = create_const_unsigned_negative(type_entry, x, negative); - TldVar *tld_var = create_global_var(c, name, var_val, true); - return &tld_var->base; -} - -static Tld *create_global_num_lit_unsigned_negative(Context *c, Buf *name, uint64_t x, bool negative) { - return create_global_num_lit_unsigned_negative_type(c, name, x, negative, c->codegen->builtin_types.entry_num_lit_int); -} - -static Tld *create_global_num_lit_float(Context *c, Buf *name, double value) { - ConstExprValue *var_val = create_const_float(c->codegen->builtin_types.entry_num_lit_float, value); - TldVar *tld_var = create_global_var(c, name, var_val, true); - return &tld_var->base; -} - -static ConstExprValue *create_const_int_ap(Context *c, TypeTableEntry *type, const Decl *source_decl, - const llvm::APSInt &aps_int) -{ - if (aps_int.isSigned()) { - if (aps_int > INT64_MAX || aps_int < INT64_MIN) { - emit_warning(c, source_decl->getLocation(), "integer overflow\n"); - return nullptr; - } else { - return create_const_signed(type, aps_int.getExtValue()); - } - } else { - if (aps_int > INT64_MAX) { - emit_warning(c, source_decl->getLocation(), "integer overflow\n"); - return nullptr; - } else { - return create_const_unsigned_negative(type, aps_int.getExtValue(), false); - } - } -} - -static Tld *create_global_num_lit_ap(Context *c, const Decl *source_decl, Buf *name, - const llvm::APSInt &aps_int) -{ - ConstExprValue *const_value = create_const_int_ap(c, c->codegen->builtin_types.entry_num_lit_int, - source_decl, aps_int); - if (!const_value) - return nullptr; - TldVar *tld_var = create_global_var(c, name, const_value, true); - return &tld_var->base; -} - - -static Tld *add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) { - ConstExprValue *var_value = create_const_type(c->codegen, type_entry); - TldVar *tld_var = create_global_var(c, name, var_value, true); - add_global(c, &tld_var->base); - - c->global_type_table.put(name, type_entry); - return &tld_var->base; -} - -static Tld *add_container_tld(Context *c, TypeTableEntry *type_entry) { - return add_const_type(c, &type_entry->name, type_entry); -} - -static bool is_c_void_type(Context *c, TypeTableEntry *type_entry) { - return (type_entry == c->codegen->builtin_types.entry_c_void); +static bool is_c_void_type(AstNode *node) { + return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); } static bool qual_type_child_is_fn_proto(const QualType &qt) { @@ -243,373 +306,6 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) { return false; } -static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const Decl *decl, - HashMap *type_table) -{ - switch (ty->getTypeClass()) { - case Type::Builtin: - { - const BuiltinType *builtin_ty = static_cast(ty); - switch (builtin_ty->getKind()) { - case BuiltinType::Void: - return c->codegen->builtin_types.entry_c_void; - case BuiltinType::Bool: - return c->codegen->builtin_types.entry_bool; - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - return c->codegen->builtin_types.entry_u8; - case BuiltinType::SChar: - return c->codegen->builtin_types.entry_i8; - case BuiltinType::UShort: - return get_c_int_type(c->codegen, CIntTypeUShort); - case BuiltinType::UInt: - return get_c_int_type(c->codegen, CIntTypeUInt); - case BuiltinType::ULong: - return get_c_int_type(c->codegen, CIntTypeULong); - case BuiltinType::ULongLong: - return get_c_int_type(c->codegen, CIntTypeULongLong); - case BuiltinType::Short: - return get_c_int_type(c->codegen, CIntTypeShort); - case BuiltinType::Int: - return get_c_int_type(c->codegen, CIntTypeInt); - case BuiltinType::Long: - return get_c_int_type(c->codegen, CIntTypeLong); - case BuiltinType::LongLong: - return get_c_int_type(c->codegen, CIntTypeLongLong); - case BuiltinType::UInt128: - return c->codegen->builtin_types.entry_u128; - case BuiltinType::Int128: - return c->codegen->builtin_types.entry_i128; - case BuiltinType::Float: - return c->codegen->builtin_types.entry_f32; - case BuiltinType::Double: - return c->codegen->builtin_types.entry_f64; - case BuiltinType::Float128: - return c->codegen->builtin_types.entry_f128; - case BuiltinType::LongDouble: - return c->codegen->builtin_types.entry_c_longdouble; - case BuiltinType::WChar_U: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::WChar_S: - case BuiltinType::Half: - case BuiltinType::NullPtr: - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - case BuiltinType::OMPArraySection: - case BuiltinType::Dependent: - case BuiltinType::Overload: - case BuiltinType::BoundMember: - case BuiltinType::PseudoObject: - case BuiltinType::UnknownAny: - case BuiltinType::BuiltinFn: - case BuiltinType::ARCUnbridgedCast: - - case BuiltinType::OCLImage1dRO: - case BuiltinType::OCLImage1dArrayRO: - case BuiltinType::OCLImage1dBufferRO: - case BuiltinType::OCLImage2dRO: - case BuiltinType::OCLImage2dArrayRO: - case BuiltinType::OCLImage2dDepthRO: - case BuiltinType::OCLImage2dArrayDepthRO: - case BuiltinType::OCLImage2dMSAARO: - case BuiltinType::OCLImage2dArrayMSAARO: - case BuiltinType::OCLImage2dMSAADepthRO: - case BuiltinType::OCLImage2dArrayMSAADepthRO: - case BuiltinType::OCLImage3dRO: - case BuiltinType::OCLImage1dWO: - case BuiltinType::OCLImage1dArrayWO: - case BuiltinType::OCLImage1dBufferWO: - case BuiltinType::OCLImage2dWO: - case BuiltinType::OCLImage2dArrayWO: - case BuiltinType::OCLImage2dDepthWO: - case BuiltinType::OCLImage2dArrayDepthWO: - case BuiltinType::OCLImage2dMSAAWO: - case BuiltinType::OCLImage2dArrayMSAAWO: - case BuiltinType::OCLImage2dMSAADepthWO: - case BuiltinType::OCLImage2dArrayMSAADepthWO: - case BuiltinType::OCLImage3dWO: - case BuiltinType::OCLImage1dRW: - case BuiltinType::OCLImage1dArrayRW: - case BuiltinType::OCLImage1dBufferRW: - case BuiltinType::OCLImage2dRW: - case BuiltinType::OCLImage2dArrayRW: - case BuiltinType::OCLImage2dDepthRW: - case BuiltinType::OCLImage2dArrayDepthRW: - case BuiltinType::OCLImage2dMSAARW: - case BuiltinType::OCLImage2dArrayMSAARW: - case BuiltinType::OCLImage2dMSAADepthRW: - case BuiltinType::OCLImage2dArrayMSAADepthRW: - case BuiltinType::OCLImage3dRW: - case BuiltinType::OCLSampler: - case BuiltinType::OCLEvent: - case BuiltinType::OCLClkEvent: - case BuiltinType::OCLQueue: - case BuiltinType::OCLReserveID: - emit_warning(c, decl->getLocation(), "missed a builtin type"); - return c->codegen->builtin_types.entry_invalid; - } - break; - } - case Type::Pointer: - { - const PointerType *pointer_ty = static_cast(ty); - QualType child_qt = pointer_ty->getPointeeType(); - TypeTableEntry *child_type = resolve_qual_type(c, child_qt, decl); - if (type_is_invalid(child_type)) { - emit_warning(c, decl->getLocation(), "pointer to unresolved type"); - return c->codegen->builtin_types.entry_invalid; - } - - if (qual_type_child_is_fn_proto(child_qt)) { - return get_maybe_type(c->codegen, child_type); - } - bool is_const = child_qt.isConstQualified(); - - TypeTableEntry *non_null_pointer_type = get_pointer_to_type(c->codegen, child_type, is_const); - return get_maybe_type(c->codegen, non_null_pointer_type); - } - case Type::Typedef: - { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); - if (buf_eql_str(type_name, "uint8_t")) { - return c->codegen->builtin_types.entry_u8; - } else if (buf_eql_str(type_name, "int8_t")) { - return c->codegen->builtin_types.entry_i8; - } else if (buf_eql_str(type_name, "uint16_t")) { - return c->codegen->builtin_types.entry_u16; - } else if (buf_eql_str(type_name, "int16_t")) { - return c->codegen->builtin_types.entry_i16; - } else if (buf_eql_str(type_name, "uint32_t")) { - return c->codegen->builtin_types.entry_u32; - } else if (buf_eql_str(type_name, "int32_t")) { - return c->codegen->builtin_types.entry_i32; - } else if (buf_eql_str(type_name, "uint64_t")) { - return c->codegen->builtin_types.entry_u64; - } else if (buf_eql_str(type_name, "int64_t")) { - return c->codegen->builtin_types.entry_i64; - } else if (buf_eql_str(type_name, "intptr_t")) { - return c->codegen->builtin_types.entry_isize; - } else if (buf_eql_str(type_name, "uintptr_t")) { - return c->codegen->builtin_types.entry_usize; - } else { - auto entry = type_table->maybe_get(type_name); - if (entry) { - if (type_is_invalid(entry->value)) { - return c->codegen->builtin_types.entry_invalid; - } else { - return entry->value; - } - } else { - return c->codegen->builtin_types.entry_invalid; - } - } - } - case Type::Elaborated: - { - const ElaboratedType *elaborated_ty = static_cast(ty); - switch (elaborated_ty->getKeyword()) { - case ETK_Struct: - return resolve_qual_type_with_table(c, elaborated_ty->getNamedType(), - decl, &c->struct_type_table); - case ETK_Enum: - return resolve_qual_type_with_table(c, elaborated_ty->getNamedType(), - decl, &c->enum_type_table); - case ETK_Interface: - case ETK_Union: - case ETK_Class: - case ETK_Typename: - case ETK_None: - emit_warning(c, decl->getLocation(), "unsupported elaborated type"); - return c->codegen->builtin_types.entry_invalid; - } - } - case Type::FunctionProto: - { - const FunctionProtoType *fn_proto_ty = static_cast(ty); - - switch (fn_proto_ty->getCallConv()) { - case CC_C: // __attribute__((cdecl)) - break; - case CC_X86StdCall: // __attribute__((stdcall)) - emit_warning(c, decl->getLocation(), "function type has x86 stdcall calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86FastCall: // __attribute__((fastcall)) - emit_warning(c, decl->getLocation(), "function type has x86 fastcall calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86ThisCall: // __attribute__((thiscall)) - emit_warning(c, decl->getLocation(), "function type has x86 thiscall calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86VectorCall: // __attribute__((vectorcall)) - emit_warning(c, decl->getLocation(), "function type has x86 vectorcall calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86Pascal: // __attribute__((pascal)) - emit_warning(c, decl->getLocation(), "function type has x86 pascal calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_Win64: // __attribute__((ms_abi)) - emit_warning(c, decl->getLocation(), "function type has win64 calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86_64SysV: // __attribute__((sysv_abi)) - emit_warning(c, decl->getLocation(), "function type has x86 64sysv calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_X86RegCall: - emit_warning(c, decl->getLocation(), "function type has x86 reg calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_AAPCS: // __attribute__((pcs("aapcs"))) - emit_warning(c, decl->getLocation(), "function type has aapcs calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) - emit_warning(c, decl->getLocation(), "function type has aapcs-vfp calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) - emit_warning(c, decl->getLocation(), "function type has intel_ocl_bicc calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_SpirFunction: // default for OpenCL functions on SPIR target - emit_warning(c, decl->getLocation(), "function type has SPIR function calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_OpenCLKernel: - emit_warning(c, decl->getLocation(), "function type has OpenCLKernel calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_Swift: - emit_warning(c, decl->getLocation(), "function type has Swift calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_PreserveMost: - emit_warning(c, decl->getLocation(), "function type has PreserveMost calling convention"); - return c->codegen->builtin_types.entry_invalid; - case CC_PreserveAll: - emit_warning(c, decl->getLocation(), "function type has PreserveAll calling convention"); - return c->codegen->builtin_types.entry_invalid; - } - - FnTypeId fn_type_id = {0}; - fn_type_id.cc = CallingConventionC; - fn_type_id.is_var_args = fn_proto_ty->isVariadic(); - fn_type_id.param_count = fn_proto_ty->getNumParams(); - - - if (fn_proto_ty->getNoReturnAttr()) { - fn_type_id.return_type = c->codegen->builtin_types.entry_unreachable; - } else { - fn_type_id.return_type = resolve_qual_type(c, fn_proto_ty->getReturnType(), decl); - if (type_is_invalid(fn_type_id.return_type)) { - emit_warning(c, decl->getLocation(), "unresolved function proto return type"); - return c->codegen->builtin_types.entry_invalid; - } - // convert c_void to actual void (only for return type) - if (is_c_void_type(c, fn_type_id.return_type)) { - fn_type_id.return_type = c->codegen->builtin_types.entry_void; - } - } - - fn_type_id.param_info = allocate_nonzero(fn_type_id.param_count); - for (size_t i = 0; i < fn_type_id.param_count; i += 1) { - QualType qt = fn_proto_ty->getParamType(i); - TypeTableEntry *param_type = resolve_qual_type(c, qt, decl); - - if (type_is_invalid(param_type)) { - emit_warning(c, decl->getLocation(), "unresolved function proto parameter type"); - return c->codegen->builtin_types.entry_invalid; - } - - FnTypeParamInfo *param_info = &fn_type_id.param_info[i]; - param_info->type = param_type; - param_info->is_noalias = qt.isRestrictQualified(); - } - - return get_fn_type(c->codegen, &fn_type_id); - } - case Type::Record: - { - const RecordType *record_ty = static_cast(ty); - return resolve_record_decl(c, record_ty->getDecl()); - } - case Type::Enum: - { - const EnumType *enum_ty = static_cast(ty); - return resolve_enum_decl(c, enum_ty->getDecl()); - } - case Type::ConstantArray: - { - const ConstantArrayType *const_arr_ty = static_cast(ty); - TypeTableEntry *child_type = resolve_qual_type(c, const_arr_ty->getElementType(), decl); - if (child_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, decl->getLocation(), "unresolved array element type"); - return child_type; - } - uint64_t size = const_arr_ty->getSize().getLimitedValue(); - return get_array_type(c->codegen, child_type, size); - } - case Type::Paren: - { - const ParenType *paren_ty = static_cast(ty); - return resolve_qual_type(c, paren_ty->getInnerType(), decl); - } - case Type::Decayed: - { - const DecayedType *decayed_ty = static_cast(ty); - return resolve_qual_type(c, decayed_ty->getDecayedType(), decl); - } - case Type::Attributed: - { - const AttributedType *attributed_ty = static_cast(ty); - return resolve_qual_type(c, attributed_ty->getEquivalentType(), decl); - } - case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: - case Type::MemberPointer: - case Type::IncompleteArray: - case Type::VariableArray: - case Type::DependentSizedArray: - case Type::DependentSizedExtVector: - case Type::Vector: - case Type::ExtVector: - case Type::FunctionNoProto: - case Type::UnresolvedUsing: - case Type::Adjusted: - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::UnaryTransform: - case Type::TemplateTypeParm: - case Type::SubstTemplateTypeParm: - case Type::SubstTemplateTypeParmPack: - case Type::TemplateSpecialization: - case Type::Auto: - case Type::InjectedClassName: - case Type::DependentName: - case Type::DependentTemplateSpecialization: - case Type::PackExpansion: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::Complex: - case Type::ObjCObjectPointer: - case Type::Atomic: - case Type::Pipe: - case Type::ObjCTypeParam: - case Type::DeducedTemplateSpecialization: - emit_warning(c, decl->getLocation(), "missed a '%s' type", ty->getTypeClassName()); - return c->codegen->builtin_types.entry_invalid; - } - zig_unreachable(); -} - -static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl, - HashMap *type_table) -{ - return resolve_type_with_table(c, qt.getTypePtr(), decl, type_table); -} - -static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl) { - return resolve_qual_type_with_table(c, qt, decl, &c->global_type_table); -} - -#include "ast_render.hpp" - static bool c_is_signed_integer(Context *c, QualType qt) { const Type *c_type = qt.getTypePtr(); if (c_type->getTypeClass() != Type::Builtin) @@ -668,19 +364,12 @@ static bool c_is_float(Context *c, QualType qt) { } static AstNode * trans_stmt(Context *c, AstNode *block, Stmt *stmt); -static AstNode * trans_create_node(Context *c, NodeType id); static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); static AstNode * trans_expr(Context *c, AstNode *block, Expr *expr) { return trans_stmt(c, block, expr); } -static AstNode *trans_create_symbol_node(Context *c, const char * name) { - AstNode *node = trans_create_node(c, NodeTypeSymbol); - node->data.symbol_expr.symbol = buf_create_from_str(name); - return node; -} - static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLocation &source_loc, HashMap *type_table) { @@ -690,43 +379,43 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo const BuiltinType *builtin_ty = static_cast(ty); switch (builtin_ty->getKind()) { case BuiltinType::Void: - return trans_create_symbol_node(c, "c_void"); + return trans_create_node_symbol_str(c, "c_void"); case BuiltinType::Bool: - return trans_create_symbol_node(c, "bool"); + return trans_create_node_symbol_str(c, "bool"); case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: - return trans_create_symbol_node(c, "u8"); + return trans_create_node_symbol_str(c, "u8"); case BuiltinType::SChar: - return trans_create_symbol_node(c, "i8"); + return trans_create_node_symbol_str(c, "i8"); case BuiltinType::UShort: - return trans_create_symbol_node(c, "c_ushort"); + return trans_create_node_symbol_str(c, "c_ushort"); case BuiltinType::UInt: - return trans_create_symbol_node(c, "c_uint"); + return trans_create_node_symbol_str(c, "c_uint"); case BuiltinType::ULong: - return trans_create_symbol_node(c, "c_ulong"); + return trans_create_node_symbol_str(c, "c_ulong"); case BuiltinType::ULongLong: - return trans_create_symbol_node(c, "c_ulonglong"); + return trans_create_node_symbol_str(c, "c_ulonglong"); case BuiltinType::Short: - return trans_create_symbol_node(c, "c_short"); + return trans_create_node_symbol_str(c, "c_short"); case BuiltinType::Int: - return trans_create_symbol_node(c, "c_int"); + return trans_create_node_symbol_str(c, "c_int"); case BuiltinType::Long: - return trans_create_symbol_node(c, "c_long"); + return trans_create_node_symbol_str(c, "c_long"); case BuiltinType::LongLong: - return trans_create_symbol_node(c, "c_longlong"); + return trans_create_node_symbol_str(c, "c_longlong"); case BuiltinType::UInt128: - return trans_create_symbol_node(c, "u128"); + return trans_create_node_symbol_str(c, "u128"); case BuiltinType::Int128: - return trans_create_symbol_node(c, "i128"); + return trans_create_node_symbol_str(c, "i128"); case BuiltinType::Float: - return trans_create_symbol_node(c, "f32"); + return trans_create_node_symbol_str(c, "f32"); case BuiltinType::Double: - return trans_create_symbol_node(c, "f64"); + return trans_create_node_symbol_str(c, "f64"); case BuiltinType::Float128: - return trans_create_symbol_node(c, "f128"); + return trans_create_node_symbol_str(c, "f128"); case BuiltinType::LongDouble: - return trans_create_symbol_node(c, "c_longdouble"); + return trans_create_node_symbol_str(c, "c_longdouble"); case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: @@ -786,7 +475,8 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: - zig_panic("TODO more c type"); + emit_warning(c, source_loc, "unsupported builtin type"); + return nullptr; } break; } @@ -795,40 +485,218 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo const PointerType *pointer_ty = static_cast(ty); QualType child_qt = pointer_ty->getPointeeType(); AstNode *child_node = trans_qual_type(c, child_qt, source_loc); - if (child_node == nullptr) return nullptr; - - if (qual_type_child_is_fn_proto(child_qt)) { - zig_panic("TODO pointer to function proto"); + if (child_node == nullptr) { + emit_warning(c, source_loc, "pointer to unsupported type"); + return nullptr; } - AstNode *pointer_node = trans_create_node(c, NodeTypeAddrOfExpr); - pointer_node->data.addr_of_expr.is_const = child_qt.isConstQualified(); - pointer_node->data.addr_of_expr.is_volatile = child_qt.isVolatileQualified(); - pointer_node->data.addr_of_expr.op_expr = child_node; + if (qual_type_child_is_fn_proto(child_qt)) { + return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); + } - AstNode *maybe_node = trans_create_node(c, NodeTypePrefixOpExpr); - maybe_node->data.prefix_op_expr.prefix_op = PrefixOpMaybe; - maybe_node->data.prefix_op_expr.primary_expr = pointer_node; - return maybe_node; + AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node); + return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); } case Type::Typedef: - zig_panic("TODO typedef"); + { + const TypedefType *typedef_ty = static_cast(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); + if (buf_eql_str(type_name, "uint8_t")) { + return trans_create_node_symbol_str(c, "u8"); + } else if (buf_eql_str(type_name, "int8_t")) { + return trans_create_node_symbol_str(c, "i8"); + } else if (buf_eql_str(type_name, "uint16_t")) { + return trans_create_node_symbol_str(c, "u16"); + } else if (buf_eql_str(type_name, "int16_t")) { + return trans_create_node_symbol_str(c, "i16"); + } else if (buf_eql_str(type_name, "uint32_t")) { + return trans_create_node_symbol_str(c, "u32"); + } else if (buf_eql_str(type_name, "int32_t")) { + return trans_create_node_symbol_str(c, "i32"); + } else if (buf_eql_str(type_name, "uint64_t")) { + return trans_create_node_symbol_str(c, "u64"); + } else if (buf_eql_str(type_name, "int64_t")) { + return trans_create_node_symbol_str(c, "i64"); + } else if (buf_eql_str(type_name, "intptr_t")) { + return trans_create_node_symbol_str(c, "isize"); + } else if (buf_eql_str(type_name, "uintptr_t")) { + return trans_create_node_symbol_str(c, "usize"); + } else { + auto entry = type_table->maybe_get(type_name); + if (entry == nullptr || entry->value == nullptr) { + return nullptr; + } else { + return entry->value; + } + } + } case Type::Elaborated: - zig_panic("TODO elaborated"); + { + const ElaboratedType *elaborated_ty = static_cast(ty); + switch (elaborated_ty->getKeyword()) { + case ETK_Struct: + return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), + source_loc, &c->struct_type_table); + case ETK_Enum: + return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), + source_loc, &c->enum_type_table); + case ETK_Interface: + case ETK_Union: + case ETK_Class: + case ETK_Typename: + case ETK_None: + emit_warning(c, source_loc, "unsupported elaborated type"); + return nullptr; + } + } case Type::FunctionProto: - zig_panic("TODO FunctionProto"); + { + const FunctionProtoType *fn_proto_ty = static_cast(ty); + + AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); + switch (fn_proto_ty->getCallConv()) { + case CC_C: // __attribute__((cdecl)) + proto_node->data.fn_proto.cc = CallingConventionC; + break; + case CC_X86StdCall: // __attribute__((stdcall)) + proto_node->data.fn_proto.cc = CallingConventionStdcall; + break; + case CC_X86FastCall: // __attribute__((fastcall)) + emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); + return nullptr; + case CC_X86ThisCall: // __attribute__((thiscall)) + emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); + return nullptr; + case CC_X86VectorCall: // __attribute__((vectorcall)) + emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); + return nullptr; + case CC_X86Pascal: // __attribute__((pascal)) + emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); + return nullptr; + case CC_Win64: // __attribute__((ms_abi)) + emit_warning(c, source_loc, "unsupported calling convention: win64"); + return nullptr; + case CC_X86_64SysV: // __attribute__((sysv_abi)) + emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); + return nullptr; + case CC_X86RegCall: + emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); + return nullptr; + case CC_AAPCS: // __attribute__((pcs("aapcs"))) + emit_warning(c, source_loc, "unsupported calling convention: aapcs"); + return nullptr; + case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) + emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); + return nullptr; + case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) + emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); + return nullptr; + case CC_SpirFunction: // default for OpenCL functions on SPIR target + emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); + return nullptr; + case CC_OpenCLKernel: + emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); + return nullptr; + case CC_Swift: + emit_warning(c, source_loc, "unsupported calling convention: Swift"); + return nullptr; + case CC_PreserveMost: + emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); + return nullptr; + case CC_PreserveAll: + emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); + return nullptr; + } + + proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); + size_t param_count = fn_proto_ty->getNumParams(); + + if (fn_proto_ty->getNoReturnAttr()) { + proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); + } else { + proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(), + source_loc); + if (proto_node->data.fn_proto.return_type == nullptr) { + emit_warning(c, source_loc, "unsupported function proto return type"); + return nullptr; + } + // convert c_void to actual void (only for return type) + if (is_c_void_type(proto_node->data.fn_proto.return_type)) { + proto_node->data.fn_proto.return_type = nullptr; + } + } + + //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); + const char *fn_name = nullptr; + if (fn_name != nullptr) { + proto_node->data.fn_proto.name = buf_create_from_str(fn_name); + } + + for (size_t i = 0; i < param_count; i += 1) { + QualType qt = fn_proto_ty->getParamType(i); + AstNode *param_type_node = trans_qual_type(c, qt, source_loc); + + if (param_type_node == nullptr) { + emit_warning(c, source_loc, "unresolved function proto parameter type"); + return nullptr; + } + + AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); + //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); + const char *param_name = nullptr; + if (param_name == nullptr) { + param_node->data.param_decl.name = buf_sprintf("arg%" ZIG_PRI_usize "", i); + } else { + param_node->data.param_decl.name = buf_create_from_str(param_name); + } + param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); + param_node->data.param_decl.type = param_type_node; + proto_node->data.fn_proto.params.append(param_node); + } + // TODO check for always_inline attribute + // TODO check for align attribute + + return proto_node; + } case Type::Record: - zig_panic("TODO Record"); + { + const RecordType *record_ty = static_cast(ty); + return resolve_record_decl(c, record_ty->getDecl()); + } case Type::Enum: - zig_panic("TODO Enum"); + { + const EnumType *enum_ty = static_cast(ty); + return resolve_enum_decl(c, enum_ty->getDecl()); + } case Type::ConstantArray: - zig_panic("TODO ConstantArray"); + { + const ConstantArrayType *const_arr_ty = static_cast(ty); + AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); + if (child_type_node == nullptr) { + emit_warning(c, source_loc, "unresolved array element type"); + return nullptr; + } + uint64_t size = const_arr_ty->getSize().getLimitedValue(); + AstNode *size_node = trans_create_node_unsigned(c, size); + return trans_create_node_array_type(c, size_node, child_type_node); + } case Type::Paren: - zig_panic("TODO Paren"); + { + const ParenType *paren_ty = static_cast(ty); + return trans_qual_type(c, paren_ty->getInnerType(), source_loc); + } case Type::Decayed: - zig_panic("TODO Decayed"); + { + const DecayedType *decayed_ty = static_cast(ty); + return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); + } case Type::Attributed: - zig_panic("TODO Attributed"); + { + const AttributedType *attributed_ty = static_cast(ty); + return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); + } case Type::BlockPointer: case Type::LValueReference: case Type::RValueReference: @@ -863,7 +731,8 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo case Type::Pipe: case Type::ObjCTypeParam: case Type::DeducedTemplateSpecialization: - zig_panic("TODO more c type aoeu"); + emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); + return nullptr; } zig_unreachable(); } @@ -875,15 +744,7 @@ static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const Sourc } static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { - return trans_qual_type_with_table(c, qt, source_loc, &c->global_type_table2); -} - -static AstNode * trans_create_node(Context *c, NodeType id) { - AstNode *node = allocate(1); - node->type = id; - node->owner = c->import; - // TODO line/column. mapping to C file?? - return node; + return trans_qual_type_with_table(c, qt, source_loc, &c->global_type_table); } static AstNode * trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { @@ -907,35 +768,15 @@ static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) } } -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 * trans_integer_literal(Context *c, IntegerLiteral *stmt) { - AstNode *node = trans_create_node(c, NodeTypeIntLiteral); +static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) { llvm::APSInt result; if (!stmt->EvaluateAsInt(result, *c->ctx)) { - fprintf(stderr, "TODO unable to convert integer literal to zig\n"); + zig_panic("TODO handle libclang unable to evaluate C integer literal"); } - node->data.int_literal.bigint = allocate(1); - aps_int_to_bigint(c, result, node->data.int_literal.bigint); - return node; + return trans_create_node_apint(c, result); } -static AstNode * trans_conditional_operator(Context *c, AstNode *block, ConditionalOperator *stmt) { +static AstNode *trans_conditional_operator(Context *c, AstNode *block, ConditionalOperator *stmt) { AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); Expr *cond_expr = stmt->getCond(); @@ -1034,9 +875,7 @@ static AstNode * trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCa return trans_expr(c, block, stmt->getSubExpr()); case CK_IntegralCast: { - AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - node->data.fn_call_expr.fn_ref_expr = trans_create_symbol_node(c, "bitCast"); - node->data.fn_call_expr.is_builtin = true; + AstNode *node = trans_create_node_builtin_fn_call_str(c, "bitCast"); node->data.fn_call_expr.params.append(trans_qual_type(c, stmt->getType(), stmt->getExprLoc())); node->data.fn_call_expr.params.append(trans_expr(c, block, stmt->getSubExpr())); return node; @@ -1166,13 +1005,6 @@ static AstNode * trans_decl_ref_expr(Context *c, DeclRefExpr *stmt) { return node; } -static AstNode * trans_create_num_lit_node_unsigned(Context *c, Stmt *stmt, uint64_t x) { - AstNode *node = trans_create_node(c, NodeTypeIntLiteral); - node->data.int_literal.bigint = allocate(1); - bigint_init_unsigned(node->data.int_literal.bigint, x); - return node; -} - static AstNode * trans_unary_operator(Context *c, AstNode *block, UnaryOperator *stmt) { switch (stmt->getOpcode()) { case UO_PostInc: @@ -1200,7 +1032,7 @@ static AstNode * trans_unary_operator(Context *c, AstNode *block, UnaryOperator } else if (c_is_unsigned_integer(c, op_expr->getType())) { // we gotta emit 0 -% x AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.op1 = trans_create_num_lit_node_unsigned(c, stmt, 0); + node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); node->data.bin_op_expr.op2 = trans_expr(c, block, op_expr); node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; return node; @@ -1230,19 +1062,14 @@ static AstNode * trans_local_declaration(Context *c, AstNode *block, DeclStmt *s switch (decl->getKind()) { case Decl::Var: { VarDecl *var_decl = (VarDecl *)decl; - AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); - node->data.variable_declaration.symbol = buf_create_from_str(decl_name(var_decl)); QualType qual_type = var_decl->getTypeSourceInfo()->getType(); - node->data.variable_declaration.is_const = qual_type.isConstQualified(); - node->data.variable_declaration.type = trans_qual_type(c, qual_type, stmt->getStartLoc()); - if (var_decl->hasInit()) { - node->data.variable_declaration.expr = trans_expr(c, block, var_decl->getInit()); - } - + AstNode *init_node = var_decl->hasInit() ? trans_expr(c, block, var_decl->getInit()) : nullptr; + AstNode *type_node = trans_qual_type(c, qual_type, stmt->getStartLoc()); + AstNode *node = trans_create_node_var_decl(c, qual_type.isConstQualified(), + buf_create_from_str(decl_name(var_decl)), type_node, init_node); block->data.block.statements.append(node); continue; } - case Decl::AccessSpec: zig_panic("TODO handle decl kind AccessSpec"); case Decl::Block: @@ -1802,53 +1629,57 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { 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 = trans_stmt(c, nullptr, body); - ast_render(c->codegen, stderr, body_node, 4); - fprintf(stderr, "\n"); - } - if (get_global(c, fn_name)) { // we already saw this function return; } - TypeTableEntry *fn_type = resolve_qual_type(c, fn_decl->getType(), fn_decl); - - if (fn_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, fn_decl->getLocation(), "ignoring function '%s' - unable to resolve type", buf_ptr(fn_name)); + AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); + if (proto_node == nullptr) { + emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); return; } - assert(fn_type->id == TypeTableEntryIdFn); - FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); - buf_init_from_buf(&fn_entry->symbol_name, fn_name); - fn_entry->type_entry = fn_type; + proto_node->data.fn_proto.name = fn_name; + proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); - assert(fn_type->data.fn.fn_type_id.cc != CallingConventionNaked); - - size_t arg_count = fn_type->data.fn.fn_type_id.param_count; - fn_entry->param_names = allocate(arg_count); - Buf *name_buf; - for (size_t i = 0; i < arg_count; i += 1) { - const ParmVarDecl *param = fn_decl->getParamDecl(i); - const char *name = decl_name(param); - if (strlen(name) == 0) { - name_buf = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } else { - name_buf = buf_create_from_str(name); - } - fn_entry->param_names[i] = name_buf; + StorageClass sc = fn_decl->getStorageClass(); + if (sc == SC_None) { + proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? VisibModExport : c->visib_mod; + } else if (sc == SC_Extern || sc == SC_Static) { + proto_node->data.fn_proto.visib_mod = c->visib_mod; + } else if (sc == SC_PrivateExtern) { + emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); + return; + } else { + emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); + return; } - TldFn *tld_fn = allocate(1); - parseh_init_tld(c, &tld_fn->base, TldIdFn, fn_name); - tld_fn->fn_entry = fn_entry; - add_global(c, &tld_fn->base); + const FunctionProtoType *fn_proto_ty = (const FunctionProtoType *) fn_decl->getType().getTypePtr(); + size_t arg_count = fn_proto_ty->getNumParams(); + for (size_t i = 0; i < arg_count; i += 1) { + AstNode *param_node = proto_node->data.fn_proto.params.at(i); + const ParmVarDecl *param = fn_decl->getParamDecl(i); + const char *name = decl_name(param); + if (strlen(name) != 0) { + param_node->data.param_decl.name = buf_create_from_str(name); + } + } - c->codegen->fn_protos.append(fn_entry); + if (fn_decl->hasBody()) { + Stmt *body = fn_decl->getBody(); + + AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); + fn_def_node->data.fn_def.fn_proto = proto_node; + fn_def_node->data.fn_def.body = trans_stmt(c, nullptr, body); + + proto_node->data.fn_proto.fn_def_node = fn_def_node; + c->root->data.root.top_level_decls.append(fn_def_node); + return; + } + + c->root->data.root.top_level_decls.append(proto_node); } static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { @@ -1874,53 +1705,36 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) // use the name of this typedef // TODO - TypeTableEntry *child_type = resolve_qual_type(c, child_qt, typedef_decl); - if (child_type->id == TypeTableEntryIdInvalid) { + AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); + if (type_node == nullptr) { emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); return; } - add_const_type(c, type_name, child_type); + add_global_var(c, type_name, type_node); + c->global_type_table.put(type_name, type_node); } -static void replace_with_fwd_decl(Context *c, TypeTableEntry *struct_type, Buf *full_type_name) { - unsigned line = c->source_node ? c->source_node->line : 0; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugForwardDeclType(c->codegen->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(full_type_name), - ZigLLVMFileToScope(c->import->di_file), c->import->di_file, line); - - ZigLLVMReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type); - struct_type->di_type = replacement_di_type; - struct_type->id = TypeTableEntryIdOpaque; -} - -static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { +static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { auto existing_entry = c->decl_table.maybe_get((void*)enum_decl); if (existing_entry) { return existing_entry->value; } const char *raw_name = decl_name(enum_decl); - - Buf *bare_name; - if (raw_name[0] == 0) { - bare_name = buf_sprintf("anon_$%" PRIu32, get_next_anon_index(c)); - } else { - bare_name = buf_create_from_str(raw_name); - } - - Buf *full_type_name = buf_sprintf("enum_%s", buf_ptr(bare_name)); + bool is_anonymous = (raw_name[0] == 0); + Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); + Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); const EnumDecl *enum_def = enum_decl->getDefinition(); if (!enum_def) { - TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindEnum, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); - enum_type->data.enumeration.zero_bits_known = true; - enum_type->data.enumeration.abi_alignment = 1; - c->enum_type_table.put(bare_name, enum_type); - c->decl_table.put(enum_decl, enum_type); - replace_with_fwd_decl(c, enum_type, full_type_name); - - return enum_type; + AstNode *opaque_node = trans_create_node_opaque(c); + if (!is_anonymous) { + c->enum_type_table.put(bare_name, opaque_node); + add_global_weak_alias(c, bare_name, opaque_node); + add_global_var(c, full_type_name, opaque_node); + } + c->decl_table.put(enum_decl, opaque_node); + return opaque_node; } bool pure_enum = true; @@ -1935,25 +1749,16 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) } } - TypeTableEntry *tag_int_type = resolve_qual_type(c, enum_decl->getIntegerType(), enum_decl); + AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); + assert(tag_int_type); if (pure_enum) { - TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindEnum, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); - TypeTableEntry *tag_type_entry = create_enum_tag_type(c->codegen, enum_type, tag_int_type); - c->enum_type_table.put(bare_name, enum_type); - c->decl_table.put(enum_decl, enum_type); - - enum_type->data.enumeration.gen_field_count = 0; - enum_type->data.enumeration.complete = true; - enum_type->data.enumeration.zero_bits_known = true; - enum_type->data.enumeration.abi_alignment = 1; - enum_type->data.enumeration.tag_type = tag_type_entry; - - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = allocate(field_count); - ZigLLVMDIEnumerator **di_enumerators = allocate(field_count); + AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); + enum_node->data.container_decl.kind = ContainerKindEnum; + enum_node->data.container_decl.layout = ContainerLayoutExtern; + enum_node->data.container_decl.init_arg_expr = tag_int_type; + enum_node->data.container_decl.fields.resize(field_count); uint32_t i = 0; for (auto it = enum_def->enumerator_begin(), it_end = enum_def->enumerator_end(); @@ -1963,92 +1768,63 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); Buf *field_name; - if (buf_starts_with_buf(enum_val_name, bare_name)) { + if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); } else { field_name = enum_val_name; } - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; - type_enum_field->name = field_name; - type_enum_field->type_entry = c->codegen->builtin_types.entry_void; - type_enum_field->value = i; - - di_enumerators[i] = ZigLLVMCreateDebugEnumerator(c->codegen->dbuilder, buf_ptr(type_enum_field->name), i); - + AstNode *field_node = trans_create_node(c, NodeTypeStructField); + field_node->data.struct_field.name = field_name; + field_node->data.struct_field.type = nullptr; + enum_node->data.container_decl.fields.items[i] = field_node; // in C each enum value is in the global namespace. so we put them there too. // at this point we can rely on the enum emitting successfully - add_global(c, create_global_num_lit_unsigned_negative(c, enum_val_name, i, false)); + AstNode *field_access_node = trans_create_node_field_access(c, + trans_create_node_symbol(c, full_type_name), field_name); + add_global_var(c, enum_val_name, field_access_node); } - // create llvm type for root struct - enum_type->type_ref = tag_type_entry->type_ref; - - enum_type->data.enumeration.abi_alignment = LLVMABIAlignmentOfType(c->codegen->target_data_ref, - enum_type->type_ref); - - // create debug type for tag - unsigned line = c->source_node ? (c->source_node->line + 1) : 0; - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, enum_type->type_ref); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, enum_type->type_ref); - ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(c->codegen->dbuilder, - ZigLLVMFileToScope(c->import->di_file), buf_ptr(bare_name), - c->import->di_file, line, - debug_size_in_bits, - debug_align_in_bits, - di_enumerators, field_count, tag_type_entry->di_type, ""); - - ZigLLVMReplaceTemporary(c->codegen->dbuilder, enum_type->di_type, tag_di_type); - enum_type->di_type = tag_di_type; - - return enum_type; - } else { - // TODO after issue #305 is solved, make this be an enum with tag_int_type - // as the integer type and set the custom enum values - TypeTableEntry *enum_type = tag_int_type; - c->enum_type_table.put(bare_name, enum_type); - c->decl_table.put(enum_decl, enum_type); - - // add variables for all the values with enum_type - for (auto it = enum_def->enumerator_begin(), - it_end = enum_def->enumerator_end(); - it != it_end; ++it) - { - const EnumConstantDecl *enum_const = *it; - - Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); - - Tld *tld = create_global_num_lit_ap(c, enum_decl, enum_val_name, enum_const->getInitVal()); - if (!tld) - return c->codegen->builtin_types.entry_invalid; - - add_global(c, tld); + if (!is_anonymous) { + c->enum_type_table.put(bare_name, enum_node); + add_global_weak_alias(c, bare_name, enum_node); + add_global_var(c, full_type_name, enum_node); } + c->decl_table.put(enum_decl, enum_node); - return enum_type; + return enum_node; } + + // TODO after issue #305 is solved, make this be an enum with tag_int_type + // as the integer type and set the custom enum values + AstNode *enum_node = tag_int_type; + + + // add variables for all the values with enum_node + for (auto it = enum_def->enumerator_begin(), + it_end = enum_def->enumerator_end(); + it != it_end; ++it) + { + const EnumConstantDecl *enum_const = *it; + + Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); + AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); + AstNode *var_node = add_global_var(c, enum_val_name, int_node); + var_node->data.variable_declaration.type = tag_int_type; + } + + if (!is_anonymous) { + c->enum_type_table.put(bare_name, enum_node); + add_global_weak_alias(c, bare_name, enum_node); + add_global_var(c, full_type_name, enum_node); + } + c->decl_table.put(enum_decl, enum_node); + + return enum_node; } -static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { - TypeTableEntry *enum_type = resolve_enum_decl(c, enum_decl); - - if (enum_type->id == TypeTableEntryIdInvalid) - return; - - // make an alias without the "enum_" prefix. this will get emitted at the - // end if it doesn't conflict with anything else - bool is_anonymous = (decl_name(enum_decl)[0] == 0); - if (is_anonymous) - return; - - Buf *bare_name = buf_create_from_str(decl_name(enum_decl)); - - Tld *tld = add_container_tld(c, enum_type); - add_global_weak_alias(c, bare_name, tld); -} - -static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl) { +static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { auto existing_entry = c->decl_table.maybe_get((void*)record_decl); if (existing_entry) { return existing_entry->value; @@ -2058,35 +1834,26 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ if (!record_decl->isStruct()) { emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); - return c->codegen->builtin_types.entry_invalid; + c->decl_table.put(record_decl, nullptr); + return nullptr; } - Buf *bare_name; - if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) { - bare_name = buf_sprintf("anon_$%" PRIu32, get_next_anon_index(c)); - } else { - bare_name = buf_create_from_str(raw_name); - } - - Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name)); - - - TypeTableEntry *struct_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindStruct, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); - struct_type->data.structure.zero_bits_known = true; - struct_type->data.structure.abi_alignment = 1; - - c->struct_type_table.put(bare_name, struct_type); - c->decl_table.put(record_decl, struct_type); + bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; + Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); + Buf *full_type_name = (bare_name == nullptr) ? nullptr : buf_sprintf("struct_%s", buf_ptr(bare_name)); RecordDecl *record_def = record_decl->getDefinition(); - unsigned line = c->source_node ? c->source_node->line : 0; - if (!record_def) { - replace_with_fwd_decl(c, struct_type, full_type_name); - return struct_type; + if (record_def == nullptr) { + AstNode *opaque_node = trans_create_node_opaque(c); + if (!is_anonymous) { + c->struct_type_table.put(bare_name, opaque_node); + add_global_weak_alias(c, bare_name, opaque_node); + add_global_var(c, full_type_name, opaque_node); + } + c->decl_table.put(record_decl, opaque_node); + return opaque_node; } - // count fields and validate uint32_t field_count = 0; for (auto it = record_def->field_begin(), @@ -2096,18 +1863,37 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ const FieldDecl *field_decl = *it; if (field_decl->isBitField()) { - emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield\n", buf_ptr(bare_name)); - replace_with_fwd_decl(c, struct_type, full_type_name); - return struct_type; + emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield", + is_anonymous ? "(anon)" : buf_ptr(bare_name)); + + AstNode *opaque_node = trans_create_node_opaque(c); + + if (!is_anonymous) { + c->struct_type_table.put(bare_name, opaque_node); + add_global_weak_alias(c, bare_name, opaque_node); + add_global_var(c, full_type_name, opaque_node); + } + c->decl_table.put(record_decl, opaque_node); + return opaque_node;; } } - struct_type->data.structure.src_field_count = field_count; - struct_type->data.structure.fields = allocate(field_count); - LLVMTypeRef *element_types = allocate(field_count); - ZigLLVMDIType **di_element_types = allocate(field_count); + AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); + struct_node->data.container_decl.kind = ContainerKindStruct; + struct_node->data.container_decl.layout = ContainerLayoutExtern; + + // TODO handle attribute packed + + struct_node->data.container_decl.fields.resize(field_count); + + // must be before fields in case a circular reference happens + if (!is_anonymous) { + c->struct_type_table.put(bare_name, struct_node); + add_global_weak_alias(c, bare_name, struct_node); + add_global_var(c, full_type_name, struct_node); + } + c->decl_table.put(record_decl, struct_node); - // next, populate element_types as its needed for LLVMStructSetBody which is needed for LLVMOffsetOfElement uint32_t i = 0; for (auto it = record_def->field_begin(), it_end = record_def->field_end(); @@ -2115,86 +1901,31 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ { const FieldDecl *field_decl = *it; - TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - type_struct_field->name = buf_create_from_str(decl_name(field_decl)); - type_struct_field->src_index = i; - type_struct_field->gen_index = i; - TypeTableEntry *field_type = resolve_qual_type(c, field_decl->getType(), field_decl); - type_struct_field->type_entry = field_type; + AstNode *field_node = trans_create_node(c, NodeTypeStructField); + field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); + field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); - if (type_is_invalid(field_type) || !type_is_complete(field_type)) { - emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - unresolved type\n", buf_ptr(bare_name)); - replace_with_fwd_decl(c, struct_type, full_type_name); - return struct_type; + if (field_node->data.struct_field.type == nullptr) { + emit_warning(c, field_decl->getLocation(), + "struct %s demoted to opaque type - unresolved type", + is_anonymous ? "(anon)" : buf_ptr(bare_name)); + + AstNode *opaque_node = trans_create_node_opaque(c); + if (!is_anonymous) { + c->struct_type_table.put(bare_name, opaque_node); + add_global_weak_alias(c, bare_name, opaque_node); + add_global_var(c, full_type_name, opaque_node); + } + c->decl_table.put(record_decl, opaque_node); + + return opaque_node; } - element_types[i] = field_type->type_ref; - assert(element_types[i]); + struct_node->data.container_decl.fields.items[i] = field_node; } - LLVMStructSetBody(struct_type->type_ref, element_types, field_count, false); - // finally populate debug info - i = 0; - for (auto it = record_def->field_begin(), - it_end = record_def->field_end(); - it != it_end; ++it, i += 1) - { - TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - TypeTableEntry *field_type = type_struct_field->type_entry; - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, field_type->type_ref); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, field_type->type_ref); - uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(c->codegen->target_data_ref, struct_type->type_ref, i); - di_element_types[i] = ZigLLVMCreateDebugMemberType(c->codegen->dbuilder, - ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name), - c->import->di_file, line + 1, - debug_size_in_bits, - debug_align_in_bits, - debug_offset_in_bits, - 0, field_type->di_type); - - assert(di_element_types[i]); - - } - struct_type->data.structure.embedded_in_current = false; - - struct_type->data.structure.gen_field_count = field_count; - struct_type->data.structure.complete = true; - struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(c->codegen->target_data_ref, - struct_type->type_ref); - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, struct_type->type_ref); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, struct_type->type_ref); - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(c->codegen->dbuilder, - ZigLLVMFileToScope(c->import->di_file), - buf_ptr(full_type_name), c->import->di_file, line + 1, - debug_size_in_bits, - debug_align_in_bits, - 0, - nullptr, di_element_types, field_count, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type); - struct_type->di_type = replacement_di_type; - - return struct_type; -} - -static void visit_record_decl(Context *c, const RecordDecl *record_decl) { - TypeTableEntry *struct_type = resolve_record_decl(c, record_decl); - - if (struct_type->id == TypeTableEntryIdInvalid) { - return; - } - - bool is_anonymous = (record_decl->isAnonymousStructOrUnion() || decl_name(record_decl)[0] == 0); - if (is_anonymous) - return; - - Buf *bare_name = buf_create_from_str(decl_name(record_decl)); - - Tld *tld = add_container_tld(c, struct_type); - add_global_weak_alias(c, bare_name, tld); + return struct_node; } static void visit_var_decl(Context *c, const VarDecl *var_decl) { @@ -2204,17 +1935,19 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { case VarDecl::TLS_None: break; case VarDecl::TLS_Static: - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - static thread local storage\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), + "ignoring variable '%s' - static thread local storage", buf_ptr(name)); return; case VarDecl::TLS_Dynamic: - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - dynamic thread local storage\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), + "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); return; } QualType qt = var_decl->getType(); - TypeTableEntry *var_type = resolve_qual_type(c, qt, var_decl); - if (var_type->id == TypeTableEntryIdInvalid) { - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type\n", buf_ptr(name)); + AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); + if (var_type == nullptr) { + emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); return; } @@ -2223,59 +1956,53 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { bool is_const = qt.isConstQualified(); if (is_static && !is_extern) { - if (!var_decl->hasInit()) { - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - no initializer\n", buf_ptr(name)); - return; - } - APValue *ap_value = var_decl->evaluateValue(); - if (!ap_value) { - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unable to evaluate initializer\n", buf_ptr(name)); - return; - } - ConstExprValue *init_value = nullptr; - switch (ap_value->getKind()) { - case APValue::Int: - { - if (var_type->id != TypeTableEntryIdInt) { - emit_warning(c, var_decl->getLocation(), - "ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name)); - return; - } - init_value = create_const_int_ap(c, var_type, var_decl, ap_value->getInt()); - if (!init_value) - return; - - break; - } - case APValue::Uninitialized: - case APValue::Float: - case APValue::ComplexInt: - case APValue::ComplexFloat: - case APValue::LValue: - case APValue::Vector: - case APValue::Array: - case APValue::Struct: - case APValue::Union: - case APValue::MemberPointer: - case APValue::AddrLabelDiff: + AstNode *init_node; + if (var_decl->hasInit()) { + APValue *ap_value = var_decl->evaluateValue(); + if (ap_value == nullptr) { emit_warning(c, var_decl->getLocation(), - "ignoring variable '%s' - unrecognized initializer value kind\n", buf_ptr(name)); + "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); return; + } + switch (ap_value->getKind()) { + case APValue::Int: + init_node = trans_create_node_apint(c, ap_value->getInt()); + break; + case APValue::Uninitialized: + init_node = trans_create_node_symbol_str(c, "undefined"); + break; + case APValue::Float: + case APValue::ComplexInt: + case APValue::ComplexFloat: + case APValue::LValue: + case APValue::Vector: + case APValue::Array: + case APValue::Struct: + case APValue::Union: + case APValue::MemberPointer: + case APValue::AddrLabelDiff: + emit_warning(c, var_decl->getLocation(), + "ignoring variable '%s' - unrecognized initializer value kind", buf_ptr(name)); + return; + } + } else { + init_node = trans_create_node_symbol_str(c, "undefined"); } - TldVar *tld_var = create_global_var(c, name, init_value, true); - add_global(c, &tld_var->base); + AstNode *var_node = trans_create_node_var_decl(c, is_const, name, var_type, init_node); + c->root->data.root.top_level_decls.append(var_node); return; } if (is_extern) { - TldVar *tld_var = create_global_var(c, name, create_const_runtime(var_type), is_const); - tld_var->var->linkage = VarLinkageExternal; - add_global(c, &tld_var->base); + AstNode *var_node = trans_create_node_var_decl(c, is_const, name, var_type, nullptr); + var_node->data.variable_declaration.is_extern = true; + c->root->data.root.top_level_decls.append(var_node); return; } - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - non-extern, non-static variable\n", buf_ptr(name)); + emit_warning(c, var_decl->getLocation(), + "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); return; } @@ -2290,25 +2017,22 @@ static bool decl_visitor(void *context, const Decl *decl) { visit_typedef_decl(c, static_cast(decl)); break; case Decl::Enum: - visit_enum_decl(c, static_cast(decl)); + resolve_enum_decl(c, static_cast(decl)); break; case Decl::Record: - visit_record_decl(c, static_cast(decl)); + resolve_record_decl(c, static_cast(decl)); break; case Decl::Var: visit_var_decl(c, static_cast(decl)); break; default: - emit_warning(c, decl->getLocation(), "ignoring %s decl\n", decl->getDeclKindName()); + emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); } return true; } static bool name_exists(Context *c, Buf *name) { - if (c->global_type_table.maybe_get(name)) { - return true; - } if (get_global(c, name)) { return true; } @@ -2324,7 +2048,7 @@ static void render_aliases(Context *c) { if (name_exists(c, alias->name)) continue; - add_global_alias(c, alias->name, alias->tld); + add_global_var(c, alias->name, alias->node); } } @@ -2335,8 +2059,7 @@ static void render_macros(Context *c) { if (!entry) break; - Tld *var_tld = entry->value; - add_global(c, var_tld); + add_global_var(c, entry->key, entry->value); } } @@ -2355,52 +2078,52 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch switch (tok->id) { case CTokIdCharLit: if (is_last && is_first) { - Tld *tld = create_global_num_lit_unsigned_negative(c, name, tok->data.char_lit, false); - c->macro_table.put(name, tld); + AstNode *node = trans_create_node_unsigned(c, tok->data.char_lit); + c->macro_table.put(name, node); } return; case CTokIdStrLit: if (is_last && is_first) { - Tld *tld = create_global_str_lit_var(c, name, buf_create_from_buf(&tok->data.str_lit)); - c->macro_table.put(name, tld); + AstNode *node = trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); + c->macro_table.put(name, node); } return; case CTokIdNumLitInt: if (is_last) { - Tld *tld; + AstNode *node; switch (tok->data.num_lit_int.suffix) { case CNumLitSuffixNone: - tld = create_global_num_lit_unsigned_negative(c, name, tok->data.num_lit_int.x, negate); + node = trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); break; case CNumLitSuffixL: - tld = create_global_num_lit_unsigned_negative_type(c, name, tok->data.num_lit_int.x, negate, - c->codegen->builtin_types.entry_c_int[CIntTypeLong]); + node = trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, + "c_long"); break; case CNumLitSuffixU: - tld = create_global_num_lit_unsigned_negative_type(c, name, tok->data.num_lit_int.x, negate, - c->codegen->builtin_types.entry_c_int[CIntTypeUInt]); + node = trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, + "c_uint"); break; case CNumLitSuffixLU: - tld = create_global_num_lit_unsigned_negative_type(c, name, tok->data.num_lit_int.x, negate, - c->codegen->builtin_types.entry_c_int[CIntTypeULong]); + node = trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, + "c_ulong"); break; case CNumLitSuffixLL: - tld = create_global_num_lit_unsigned_negative_type(c, name, tok->data.num_lit_int.x, negate, - c->codegen->builtin_types.entry_c_int[CIntTypeLongLong]); + node = trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, + "c_longlong"); break; case CNumLitSuffixLLU: - tld = create_global_num_lit_unsigned_negative_type(c, name, tok->data.num_lit_int.x, negate, - c->codegen->builtin_types.entry_c_int[CIntTypeULongLong]); + node = trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, + "c_ulonglong"); break; } - c->macro_table.put(name, tld); + c->macro_table.put(name, node); } return; case CTokIdNumLitFloat: if (is_last) { double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; - Tld *tld = create_global_num_lit_float(c, name, value); - c->macro_table.put(name, tld); + AstNode *node = trans_create_node_float_lit(c, value); + c->macro_table.put(name, node); } return; case CTokIdSymbol: @@ -2429,29 +2152,29 @@ static void process_symbol_macros(Context *c) { for (size_t i = 0; i < c->macro_symbols.length; i += 1) { MacroSymbol ms = c->macro_symbols.at(i); - // If this macro aliases another top level declaration, we can make that happen by - // putting another entry in the decl table pointing to the same top level decl. - Tld *existing_tld = get_global(c, ms.value); - if (!existing_tld) + // Check if this macro aliases another top level declaration + AstNode *existing_node = get_global(c, ms.value); + if (!existing_node || name_exists(c, ms.name)) continue; // If a macro aliases a global variable which is a function pointer, we conclude that // the macro is intended to represent a function that assumes the function pointer // variable is non-null and calls it. - if (existing_tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)existing_tld; - TypeTableEntry *var_type = tld_var->var->value->type; - if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) { - TypeTableEntry *child_type = var_type->data.maybe.child_type; - if (child_type->id == TypeTableEntryIdFn) { - Tld *tld = create_inline_fn_tld(c, ms.name, tld_var); - c->macro_table.put(ms.name, tld); + if (existing_node->type == NodeTypeVariableDeclaration) { + AstNode *var_expr = existing_node->data.variable_declaration.expr; + if (var_expr != nullptr && var_expr->type == NodeTypePrefixOpExpr && + var_expr->data.prefix_op_expr.prefix_op == PrefixOpMaybe) + { + AstNode *fn_proto_node = var_expr->data.prefix_op_expr.primary_expr; + if (fn_proto_node->type == NodeTypeFnProto) { + AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node); + c->macro_table.put(ms.name, inline_fn_node); continue; } } } - add_global_alias(c, ms.name, existing_tld); + add_global_var(c, ms.name, existing_node); } } @@ -2651,15 +2374,17 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->ctx = &ast_unit->getASTContext(); c->source_manager = &ast_unit->getSourceManager(); + c->root = trans_create_node(c, NodeTypeRoot); ast_unit->visitLocalTopLevelDecls(c, decl_visitor); process_preprocessor_entities(c, *ast_unit); - process_symbol_macros(c); - render_macros(c); + process_symbol_macros(c); render_aliases(c); + import->root = c->root; + return 0; } diff --git a/test/parseh.zig b/test/parseh.zig index 08889c1f2b..3c109843b3 100644 --- a/test/parseh.zig +++ b/test/parseh.zig @@ -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 = Foo.A; , - \\pub const FooB = 1; + \\pub const FooB = Foo.B; , - \\pub const Foo1 = 2; + \\pub const Foo1 = Foo.1; , - \\pub const Foo = enum_Foo + \\pub const Foo = enum_Foo; ); cases.add("restrict -> noalias", From cc621cdee3da956e0976e656d4d310fcad441dad Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 00:21:02 -0400 Subject: [PATCH 10/16] fix parseh bugs --- src/ast_render.cpp | 9 ++- src/errmsg.cpp | 7 ++- src/parseh.cpp | 148 +++++++++++++++++++++++++-------------------- src/parser.cpp | 6 +- test/parseh.zig | 10 +-- 5 files changed, 100 insertions(+), 80 deletions(-) diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 8df4dc0436..1ac9d8de79 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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); diff --git a/src/errmsg.cpp b/src/errmsg.cpp index ef61d09740..91a12fda4e 100644 --- a/src/errmsg.cpp +++ b/src/errmsg.cpp @@ -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; diff --git a/src/parseh.cpp b/src/parseh.cpp index e466e5bb73..bd3e4a30ae 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -30,8 +30,8 @@ struct MacroSymbol { }; struct Alias { - Buf *name; - AstNode *node; + Buf *new_name; + Buf *canon_name; }; struct Context { @@ -85,10 +85,10 @@ static void emit_warning(Context *c, const SourceLocation &sl, const char *forma fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); } -static void add_global_weak_alias(Context *c, Buf *name, AstNode *node) { +static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { Alias *alias = c->aliases.add_one(); - alias->name = name; - alias->node = node; + alias->new_name = new_name; + alias->canon_name = canon_name; } static AstNode * trans_create_node(Context *c, NodeType id) { @@ -128,7 +128,7 @@ static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *na } static AstNode *trans_create_node_opaque(Context *c) { - return trans_create_node_builtin_fn_call_str(c, "opaque"); + return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); } static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { @@ -209,7 +209,7 @@ static AstNode *trans_create_node_var_decl(Context *c, bool is_const, Buf *var_n static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); - fn_proto->data.fn_proto.visib_mod = c->visib_mod;; + fn_proto->data.fn_proto.visib_mod = c->visib_mod; fn_proto->data.fn_proto.name = fn_name; fn_proto->data.fn_proto.is_inline = true; fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? @@ -559,6 +559,7 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo switch (fn_proto_ty->getCallConv()) { case CC_C: // __attribute__((cdecl)) proto_node->data.fn_proto.cc = CallingConventionC; + proto_node->data.fn_proto.is_extern = true; break; case CC_X86StdCall: // __attribute__((stdcall)) proto_node->data.fn_proto.cc = CallingConventionStdcall; @@ -646,9 +647,7 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); const char *param_name = nullptr; - if (param_name == nullptr) { - param_node->data.param_decl.name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } else { + if (param_name != nullptr) { param_node->data.param_decl.name = buf_create_from_str(param_name); } param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); @@ -1662,7 +1661,14 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { AstNode *param_node = proto_node->data.fn_proto.params.at(i); const ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); - if (strlen(name) != 0) { + if (strlen(name) == 0) { + Buf *proto_param_name = param_node->data.param_decl.name; + if (proto_param_name == nullptr) { + param_node->data.param_decl.name = buf_sprintf("arg%" ZIG_PRI_usize "", i); + } else { + param_node->data.param_decl.name = proto_param_name; + } + } else { param_node->data.param_decl.name = buf_create_from_str(name); } } @@ -1714,6 +1720,22 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) c->global_type_table.put(type_name, type_node); } +struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, + Buf *full_type_name, Buf *bare_name) +{ + AstNode *opaque_node = trans_create_node_opaque(c); + if (full_type_name == nullptr) { + c->decl_table.put(enum_decl, opaque_node); + return opaque_node; + } + AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); + c->enum_type_table.put(bare_name, symbol_node); + add_global_weak_alias(c, bare_name, full_type_name); + add_global_var(c, full_type_name, opaque_node); + c->decl_table.put(enum_decl, symbol_node); + return symbol_node; +} + static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { auto existing_entry = c->decl_table.maybe_get((void*)enum_decl); if (existing_entry) { @@ -1727,14 +1749,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { const EnumDecl *enum_def = enum_decl->getDefinition(); if (!enum_def) { - AstNode *opaque_node = trans_create_node_opaque(c); - if (!is_anonymous) { - c->enum_type_table.put(bare_name, opaque_node); - add_global_weak_alias(c, bare_name, opaque_node); - add_global_var(c, full_type_name, opaque_node); - } - c->decl_table.put(enum_decl, opaque_node); - return opaque_node; + return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); } bool pure_enum = true; @@ -1786,14 +1801,17 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { add_global_var(c, enum_val_name, field_access_node); } - if (!is_anonymous) { - c->enum_type_table.put(bare_name, enum_node); - add_global_weak_alias(c, bare_name, enum_node); + if (is_anonymous) { + c->decl_table.put(enum_decl, enum_node); + return enum_node; + } else { + AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); + c->enum_type_table.put(bare_name, symbol_node); + add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); + c->decl_table.put(enum_decl, symbol_node); + return enum_node; } - c->decl_table.put(enum_decl, enum_node); - - return enum_node; } // TODO after issue #305 is solved, make this be an enum with tag_int_type @@ -1814,14 +1832,32 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { var_node->data.variable_declaration.type = tag_int_type; } - if (!is_anonymous) { - c->enum_type_table.put(bare_name, enum_node); - add_global_weak_alias(c, bare_name, enum_node); + if (is_anonymous) { + c->decl_table.put(enum_decl, enum_node); + return enum_node; + } else { + AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); + c->enum_type_table.put(bare_name, symbol_node); + add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); + return symbol_node; } - c->decl_table.put(enum_decl, enum_node); +} - return enum_node; +static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, + Buf *full_type_name, Buf *bare_name) +{ + AstNode *opaque_node = trans_create_node_opaque(c); + if (full_type_name == nullptr) { + c->decl_table.put(record_decl, opaque_node); + return opaque_node; + } + AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); + c->struct_type_table.put(bare_name, symbol_node); + add_global_weak_alias(c, bare_name, full_type_name); + add_global_var(c, full_type_name, opaque_node); + c->decl_table.put(record_decl, symbol_node); + return symbol_node; } static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { @@ -1834,7 +1870,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (!record_decl->isStruct()) { emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); - c->decl_table.put(record_decl, nullptr); return nullptr; } @@ -1844,14 +1879,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { RecordDecl *record_def = record_decl->getDefinition(); if (record_def == nullptr) { - AstNode *opaque_node = trans_create_node_opaque(c); - if (!is_anonymous) { - c->struct_type_table.put(bare_name, opaque_node); - add_global_weak_alias(c, bare_name, opaque_node); - add_global_var(c, full_type_name, opaque_node); - } - c->decl_table.put(record_decl, opaque_node); - return opaque_node; + return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); } // count fields and validate @@ -1865,16 +1893,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (field_decl->isBitField()) { emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield", is_anonymous ? "(anon)" : buf_ptr(bare_name)); - - AstNode *opaque_node = trans_create_node_opaque(c); - - if (!is_anonymous) { - c->struct_type_table.put(bare_name, opaque_node); - add_global_weak_alias(c, bare_name, opaque_node); - add_global_var(c, full_type_name, opaque_node); - } - c->decl_table.put(record_decl, opaque_node); - return opaque_node;; + return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); } } @@ -1887,12 +1906,14 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { struct_node->data.container_decl.fields.resize(field_count); // must be before fields in case a circular reference happens - if (!is_anonymous) { + if (is_anonymous) { + c->decl_table.put(record_decl, struct_node); + } else { c->struct_type_table.put(bare_name, struct_node); - add_global_weak_alias(c, bare_name, struct_node); + add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, struct_node); + c->decl_table.put(record_decl, trans_create_node_symbol(c, full_type_name)); } - c->decl_table.put(record_decl, struct_node); uint32_t i = 0; for (auto it = record_def->field_begin(), @@ -1910,22 +1931,17 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { "struct %s demoted to opaque type - unresolved type", is_anonymous ? "(anon)" : buf_ptr(bare_name)); - AstNode *opaque_node = trans_create_node_opaque(c); - if (!is_anonymous) { - c->struct_type_table.put(bare_name, opaque_node); - add_global_weak_alias(c, bare_name, opaque_node); - add_global_var(c, full_type_name, opaque_node); - } - c->decl_table.put(record_decl, opaque_node); - - return opaque_node; + return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); } struct_node->data.container_decl.fields.items[i] = field_node; } - - return struct_node; + if (is_anonymous) { + return struct_node; + } else { + return trans_create_node_symbol(c, full_type_name); + } } static void visit_var_decl(Context *c, const VarDecl *var_decl) { @@ -2045,10 +2061,10 @@ static bool name_exists(Context *c, Buf *name) { static void render_aliases(Context *c) { for (size_t i = 0; i < c->aliases.length; i += 1) { Alias *alias = &c->aliases.at(i); - if (name_exists(c, alias->name)) + if (name_exists(c, alias->new_name)) continue; - add_global_var(c, alias->name, alias->node); + add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); } } @@ -2174,7 +2190,7 @@ static void process_symbol_macros(Context *c) { } } - add_global_var(c, ms.name, existing_node); + add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value)); } } diff --git a/src/parser.cpp b/src/parser.cpp index 75d4dd309c..c47d6a4789 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -22,7 +22,6 @@ struct ParseContext { ErrColor err_color; // These buffers are used freqently so we preallocate them once here. Buf *void_buf; - Buf *empty_buf; }; __attribute__ ((format (printf, 4, 5))) @@ -276,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); @@ -2246,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); @@ -2612,7 +2611,6 @@ AstNode *ast_parse(Buf *buf, ZigList *tokens, ImportTableEntry *owner, { 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; diff --git a/test/parseh.zig b/test/parseh.zig index 3c109843b3..a2f4602ed8 100644 --- a/test/parseh.zig +++ b/test/parseh.zig @@ -44,11 +44,11 @@ pub fn addCases(cases: &tests.ParseHContext) { \\ @"1", \\}; , - \\pub const FooA = Foo.A; + \\pub const FooA = enum_Foo.A; , - \\pub const FooB = Foo.B; + \\pub const FooB = enum_Foo.B; , - \\pub const Foo1 = Foo.1; + \\pub const Foo1 = enum_Foo.@"1"; , \\pub const Foo = enum_Foo; ); @@ -94,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); , From b64843bf702dcae9fc6a7f3570282a4ddf10af56 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 00:45:09 -0400 Subject: [PATCH 11/16] parseh: fix generating functions from macros --- src/parseh.cpp | 21 ++++++++++++++------- test/parseh.zig | 8 ++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index bd3e4a30ae..101226f38d 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -224,6 +224,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); Buf *param_name = src_param_node->data.param_decl.name; + if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); dest_param_node->data.param_decl.name = param_name; @@ -238,6 +239,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n AstNode *block = trans_create_node(c, NodeTypeBlock); block->data.block.statements.resize(1); block->data.block.statements.items[0] = fn_call_node; + block->data.block.last_statement_is_result_expression = true; fn_def->data.fn_def.body = block; return fn_def; @@ -2075,7 +2077,12 @@ static void render_macros(Context *c) { if (!entry) break; - add_global_var(c, entry->key, entry->value); + AstNode *value_node = entry->value; + if (value_node->type == NodeTypeFnDef) { + c->root->data.root.top_level_decls.append(value_node); + } else { + add_global_var(c, entry->key, value_node); + } } } @@ -2170,18 +2177,18 @@ static void process_symbol_macros(Context *c) { // Check if this macro aliases another top level declaration AstNode *existing_node = get_global(c, ms.value); - if (!existing_node || name_exists(c, ms.name)) + if (!existing_node) continue; // If a macro aliases a global variable which is a function pointer, we conclude that // the macro is intended to represent a function that assumes the function pointer // variable is non-null and calls it. if (existing_node->type == NodeTypeVariableDeclaration) { - AstNode *var_expr = existing_node->data.variable_declaration.expr; - if (var_expr != nullptr && var_expr->type == NodeTypePrefixOpExpr && - var_expr->data.prefix_op_expr.prefix_op == PrefixOpMaybe) + AstNode *var_type = existing_node->data.variable_declaration.type; + if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr && + var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe) { - AstNode *fn_proto_node = var_expr->data.prefix_op_expr.primary_expr; + AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr; if (fn_proto_node->type == NodeTypeFnProto) { AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node); c->macro_table.put(ms.name, inline_fn_node); @@ -2396,8 +2403,8 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch process_preprocessor_entities(c, *ast_unit); - render_macros(c); process_symbol_macros(c); + render_macros(c); render_aliases(c); import->root = c->root; diff --git a/test/parseh.zig b/test/parseh.zig index a2f4602ed8..acab17e1e1 100644 --- a/test/parseh.zig +++ b/test/parseh.zig @@ -202,11 +202,15 @@ 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", From f6c271f8ebb990eafb598acf8d9ced1e7ade42db Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 00:52:05 -0400 Subject: [PATCH 12/16] parseh tests passing --- test/parseh.zig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/parseh.zig b/test/parseh.zig index acab17e1e1..6e472f5daf 100644 --- a/test/parseh.zig +++ b/test/parseh.zig @@ -216,7 +216,7 @@ pub fn addCases(cases: &tests.ParseHContext) { 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", @@ -234,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", @@ -290,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; ); From 5c386f99117230ff84d177395d6e14645f61bf2d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 01:22:26 -0400 Subject: [PATCH 13/16] parseh: remove unneeded hash tables --- src/parseh.cpp | 130 +++++++++++++++++++++--------------------------- test/parseh.zig | 2 +- 2 files changed, 57 insertions(+), 75 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 101226f38d..082cf30233 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -40,9 +40,6 @@ struct Context { bool warnings_on; VisibMod visib_mod; AstNode *root; - HashMap global_type_table; - HashMap struct_type_table; - HashMap enum_type_table; HashMap decl_table; HashMap macro_table; SourceManager *source_manager; @@ -56,9 +53,9 @@ struct Context { static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); -static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc, - HashMap *type_table); -static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); +static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); +static AstNode *trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc); +static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); __attribute__ ((format (printf, 3, 4))) @@ -372,9 +369,7 @@ static AstNode * trans_expr(Context *c, AstNode *block, Expr *expr) { return trans_stmt(c, block, expr); } -static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLocation &source_loc, - HashMap *type_table) -{ +static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLocation &source_loc) { switch (ty->getTypeClass()) { case Type::Builtin: { @@ -504,46 +499,16 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo { const TypedefType *typedef_ty = static_cast(ty); const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); - if (buf_eql_str(type_name, "uint8_t")) { - return trans_create_node_symbol_str(c, "u8"); - } else if (buf_eql_str(type_name, "int8_t")) { - return trans_create_node_symbol_str(c, "i8"); - } else if (buf_eql_str(type_name, "uint16_t")) { - return trans_create_node_symbol_str(c, "u16"); - } else if (buf_eql_str(type_name, "int16_t")) { - return trans_create_node_symbol_str(c, "i16"); - } else if (buf_eql_str(type_name, "uint32_t")) { - return trans_create_node_symbol_str(c, "u32"); - } else if (buf_eql_str(type_name, "int32_t")) { - return trans_create_node_symbol_str(c, "i32"); - } else if (buf_eql_str(type_name, "uint64_t")) { - return trans_create_node_symbol_str(c, "u64"); - } else if (buf_eql_str(type_name, "int64_t")) { - return trans_create_node_symbol_str(c, "i64"); - } else if (buf_eql_str(type_name, "intptr_t")) { - return trans_create_node_symbol_str(c, "isize"); - } else if (buf_eql_str(type_name, "uintptr_t")) { - return trans_create_node_symbol_str(c, "usize"); - } else { - auto entry = type_table->maybe_get(type_name); - if (entry == nullptr || entry->value == nullptr) { - return nullptr; - } else { - return entry->value; - } - } + return resolve_typedef_decl(c, typedef_decl); } case Type::Elaborated: { const ElaboratedType *elaborated_ty = static_cast(ty); switch (elaborated_ty->getKeyword()) { case ETK_Struct: - return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), - source_loc, &c->struct_type_table); + return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), source_loc); case ETK_Enum: - return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), - source_loc, &c->enum_type_table); + return trans_qual_type_with_table(c, elaborated_ty->getNamedType(), source_loc); case ETK_Interface: case ETK_Union: case ETK_Class: @@ -738,14 +703,12 @@ static AstNode *trans_type_with_table(Context *c, const Type *ty, const SourceLo zig_unreachable(); } -static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc, - HashMap *type_table) -{ - return trans_type_with_table(c, qt.getTypePtr(), source_loc, type_table); +static AstNode * trans_qual_type_with_table(Context *c, QualType qt, const SourceLocation &source_loc) { + return trans_type_with_table(c, qt.getTypePtr(), source_loc); } static AstNode * trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { - return trans_qual_type_with_table(c, qt, source_loc, &c->global_type_table); + return trans_qual_type_with_table(c, qt, source_loc); } static AstNode * trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { @@ -1690,23 +1653,45 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { c->root->data.root.top_level_decls.append(proto_node); } -static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { +static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { + AstNode *node = trans_create_node_symbol_str(c, primitive_name); + c->decl_table.put(typedef_decl, node); + return node; +} + +static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { + auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl); + if (existing_entry) { + return existing_entry->value; + } + QualType child_qt = typedef_decl->getUnderlyingType(); Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); - if (buf_eql_str(type_name, "uint8_t") || - buf_eql_str(type_name, "int8_t") || - buf_eql_str(type_name, "uint16_t") || - buf_eql_str(type_name, "int16_t") || - buf_eql_str(type_name, "uint32_t") || - buf_eql_str(type_name, "int32_t") || - buf_eql_str(type_name, "uint64_t") || - buf_eql_str(type_name, "int64_t") || - buf_eql_str(type_name, "intptr_t") || - buf_eql_str(type_name, "uintptr_t")) - { - // special case we can just use the builtin types - return; + if (buf_eql_str(type_name, "uint8_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "u8"); + } else if (buf_eql_str(type_name, "int8_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "i8"); + } else if (buf_eql_str(type_name, "uint16_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "u16"); + } else if (buf_eql_str(type_name, "int16_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "i16"); + } else if (buf_eql_str(type_name, "uint32_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "u32"); + } else if (buf_eql_str(type_name, "int32_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "i32"); + } else if (buf_eql_str(type_name, "uint64_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "u64"); + } else if (buf_eql_str(type_name, "int64_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "i64"); + } else if (buf_eql_str(type_name, "intptr_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "isize"); + } else if (buf_eql_str(type_name, "uintptr_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "usize"); + } else if (buf_eql_str(type_name, "ssize_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "isize"); + } else if (buf_eql_str(type_name, "size_t")) { + return resolve_typdef_as_builtin(c, typedef_decl, "usize"); } // if the underlying type is anonymous, we can special case it to just @@ -1716,10 +1701,14 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); if (type_node == nullptr) { emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); - return; + c->decl_table.put(typedef_decl, nullptr); + return nullptr; } add_global_var(c, type_name, type_node); - c->global_type_table.put(type_name, type_node); + + AstNode *symbol_node = trans_create_node_symbol(c, type_name); + c->decl_table.put(typedef_decl, symbol_node); + return symbol_node; } struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, @@ -1731,7 +1720,6 @@ struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - c->enum_type_table.put(bare_name, symbol_node); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); c->decl_table.put(enum_decl, symbol_node); @@ -1808,7 +1796,6 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { return enum_node; } else { AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - c->enum_type_table.put(bare_name, symbol_node); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); c->decl_table.put(enum_decl, symbol_node); @@ -1839,7 +1826,6 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { return enum_node; } else { AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - c->enum_type_table.put(bare_name, symbol_node); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); return symbol_node; @@ -1855,7 +1841,6 @@ static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_dec return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - c->struct_type_table.put(bare_name, symbol_node); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); c->decl_table.put(record_decl, symbol_node); @@ -1872,6 +1857,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (!record_decl->isStruct()) { emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); + c->decl_table.put(record_decl, nullptr); return nullptr; } @@ -1911,9 +1897,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (is_anonymous) { c->decl_table.put(record_decl, struct_node); } else { - c->struct_type_table.put(bare_name, struct_node); - add_global_weak_alias(c, bare_name, full_type_name); - add_global_var(c, full_type_name, struct_node); c->decl_table.put(record_decl, trans_create_node_symbol(c, full_type_name)); } @@ -1942,6 +1925,8 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (is_anonymous) { return struct_node; } else { + add_global_weak_alias(c, bare_name, full_type_name); + add_global_var(c, full_type_name, struct_node); return trans_create_node_symbol(c, full_type_name); } } @@ -2032,7 +2017,7 @@ static bool decl_visitor(void *context, const Decl *decl) { visit_fn_decl(c, static_cast(decl)); break; case Decl::Typedef: - visit_typedef_decl(c, static_cast(decl)); + resolve_typedef_decl(c, static_cast(decl)); break; case Decl::Enum: resolve_enum_decl(c, static_cast(decl)); @@ -2260,9 +2245,6 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->import = import; c->errors = errors; c->visib_mod = VisibModPub; - c->global_type_table.init(8); - c->enum_type_table.init(8); - c->struct_type_table.init(8); c->decl_table.init(8); c->macro_table.init(8); c->codegen = codegen; diff --git a/test/parseh.zig b/test/parseh.zig index 6e472f5daf..d71758bedf 100644 --- a/test/parseh.zig +++ b/test/parseh.zig @@ -190,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", From 87970920c493de2f2d4606dfef92bb847e07105f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 02:34:06 -0400 Subject: [PATCH 14/16] parseh: fix duplicate definitions --- src/parseh.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/parseh.cpp b/src/parseh.cpp index 082cf30233..bfc5ee7dda 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -1716,18 +1716,18 @@ struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, { AstNode *opaque_node = trans_create_node_opaque(c); if (full_type_name == nullptr) { - c->decl_table.put(enum_decl, opaque_node); + c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(enum_decl, symbol_node); + c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); return symbol_node; } static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)enum_decl); + auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; } @@ -1792,13 +1792,13 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { } if (is_anonymous) { - c->decl_table.put(enum_decl, enum_node); + c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); return enum_node; } else { AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); - c->decl_table.put(enum_decl, symbol_node); + c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); return enum_node; } } @@ -1822,7 +1822,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { } if (is_anonymous) { - c->decl_table.put(enum_decl, enum_node); + c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); return enum_node; } else { AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); @@ -1837,18 +1837,18 @@ static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_dec { AstNode *opaque_node = trans_create_node_opaque(c); if (full_type_name == nullptr) { - c->decl_table.put(record_decl, opaque_node); + c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(record_decl, symbol_node); + c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); return symbol_node; } static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)record_decl); + auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; } @@ -1857,7 +1857,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { if (!record_decl->isStruct()) { emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); - c->decl_table.put(record_decl, nullptr); + c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); return nullptr; } @@ -1895,9 +1895,9 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { // must be before fields in case a circular reference happens if (is_anonymous) { - c->decl_table.put(record_decl, struct_node); + c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); } else { - c->decl_table.put(record_decl, trans_create_node_symbol(c, full_type_name)); + c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); } uint32_t i = 0; @@ -2189,6 +2189,8 @@ static void process_symbol_macros(Context *c) { static void process_preprocessor_entities(Context *c, ASTUnit &unit) { CTokenize ctok = {{0}}; + // TODO if we see #undef, delete it from the table + for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { switch (entity->getKind()) { case PreprocessedEntity::InvalidKind: From c3362c1cb63ff8d8e79a16c76a574bbbd488967c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 03:11:59 -0400 Subject: [PATCH 15/16] fix void return node and param name nodes, fix dupe macros all tests passing --- src/analyze.cpp | 10 +++++++--- src/ir.cpp | 2 +- src/parseh.cpp | 14 +++----------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b3e9601102..322bb2f4ba 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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; diff --git a/src/ir.cpp b/src/ir.cpp index 4049295815..11e02d4cc7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6116,7 +6116,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *return_type; if (node->data.fn_proto.return_type == nullptr) { - return_type = ir_build_const_void(irb, parent_scope, node); + 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) diff --git a/src/parseh.cpp b/src/parseh.cpp index bfc5ee7dda..f7e0b909c7 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -1620,9 +1620,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { return; } - const FunctionProtoType *fn_proto_ty = (const FunctionProtoType *) fn_decl->getType().getTypePtr(); - size_t arg_count = fn_proto_ty->getNumParams(); - for (size_t i = 0; i < arg_count; i += 1) { + for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { AstNode *param_node = proto_node->data.fn_proto.params.at(i); const ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); @@ -2036,13 +2034,7 @@ static bool decl_visitor(void *context, const Decl *decl) { } static bool name_exists(Context *c, Buf *name) { - if (get_global(c, name)) { - return true; - } - if (c->macro_table.maybe_get(name)) { - return true; - } - return false; + return get_global(c, name) != nullptr; } static void render_aliases(Context *c) { @@ -2162,7 +2154,7 @@ static void process_symbol_macros(Context *c) { // Check if this macro aliases another top level declaration AstNode *existing_node = get_global(c, ms.value); - if (!existing_node) + if (!existing_node || name_exists(c, ms.name)) continue; // If a macro aliases a global variable which is a function pointer, we conclude that From 3ff465e2883b556cd08afc08b0a2098255314d4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Sep 2017 18:51:07 -0400 Subject: [PATCH 16/16] add OpaqueType builtin closes #326 --- src/all_types.hpp | 6 ++++ src/codegen.cpp | 5 +++- src/ir.cpp | 66 ++++++++++++++++++++++++++++++----------- src/ir_print.cpp | 7 +++++ test/cases/misc.zig | 8 +++++ test/compile_errors.zig | 11 +++++++ 6 files changed, 85 insertions(+), 18 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index a4e86c6b20..f301b724d4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1253,6 +1253,7 @@ enum BuiltinFnId { BuiltinFnIdShrExact, BuiltinFnIdSetEvalBranchQuota, BuiltinFnIdAlignCast, + BuiltinFnIdOpaqueType, }; struct BuiltinFnEntry { @@ -1858,6 +1859,7 @@ enum IrInstructionId { IrInstructionIdSetEvalBranchQuota, IrInstructionIdPtrTypeOf, IrInstructionIdAlignCast, + IrInstructionIdOpaqueType, }; struct IrInstruction { @@ -2648,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; diff --git a/src/codegen.cpp b/src/codegen.cpp index a53174ab89..eacb303956 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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) { diff --git a/src/ir.cpp b/src/ir.cpp index 11e02d4cc7..a8c1409ef0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -559,6 +559,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) { return IrInstructionIdAlignCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { + return IrInstructionIdOpaqueType; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(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(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(1); @@ -15143,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: @@ -15329,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(); } @@ -15507,6 +15538,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdOffsetOf: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: + case IrInstructionIdOpaqueType: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 52fb675515..fccf11038a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -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"); } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index ee9833320d..a968fd213c 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -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")); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2ab26c0078..93be0e176e 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -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'"); + }