diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..e6e2c5bf --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +TabWidth: 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..623cd141 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.clay linguist-language=JavaScript diff --git a/.gitignore b/.gitignore index a9316691..89e59f99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ .DS_Store Thumbs.db *.pdb -.vscode/ +.vscode/*.code-workspace +.cache/ +compile_commands.json *.swp *.swo *.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8388526f..e94311b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") find_package(Git) @@ -35,17 +36,19 @@ if(UNIX) if (NOT ${LLVM_CONFIG_VERSION_RESULT} EQUAL 0) message(FATAL_ERROR "${LLVM_CONFIG} failed") endif() + if(LLVM_VERSION VERSION_LESS 18.0) + message(FATAL_ERROR "LLVM 18 or newer is required. Found ${LLVM_VERSION}") + endif() execute_process( COMMAND ${LLVM_CONFIG} --cxxflags OUTPUT_VARIABLE LLVM_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") separate_arguments(LLVM_CXXFLAGS) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -O0") + list(APPEND LLVM_CXXFLAGS -O0) endif() execute_process( @@ -79,7 +82,6 @@ if(UNIX) OUTPUT_VARIABLE LLVM_INCLUDEDIR OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_INCLUDEDIR "${LLVM_INCLUDEDIR}") message("-- Using LLVM: ${LLVM_DIR}") message("-- LLVM include dir: ${LLVM_INCLUDEDIR}") @@ -90,6 +92,7 @@ if(UNIX) elseif(WIN32) + # TODO: unverified, port to find_package(LLVM CONFIG) + llvm_map_components_to_libnames. set(LLVM_DIR "$ENV{ProgramFiles}/LLVM" CACHE PATH "llvm install path") if(IS_DIRECTORY ${LLVM_DIR}) @@ -115,10 +118,6 @@ elseif(WIN32) endif() -set(BUILD_BINDGEN True CACHE BOOL - "Build the clay-bindgen tool for generating Clay bindings from C header files." -) - install(DIRECTORY doc/ DESTINATION share/doc/clay) install(DIRECTORY examples/ DESTINATION share/doc/clay/examples) install(DIRECTORY lib-clay DESTINATION lib) diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 2868281a..2b750204 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -54,41 +54,56 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") COMPILE_DEFINITIONS "GIT_ID=\"${GIT_WC_ID}\"") endif() -# Compiler flags +# Targets +add_library(compiler STATIC ${COMPILER_SOURCES}) +add_executable(clay ${CLAY_SOURCES}) +add_executable(claydoc ${CLAYDOC_SOURCES}) +add_executable(ut ${UT_SOURCES}) + +# compiler flags +target_compile_options(compiler PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(clay PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(claydoc PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(ut PRIVATE ${LLVM_CXXFLAGS}) + +# include directories +target_include_directories(compiler PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(clay PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(claydoc PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(ut PRIVATE ${LLVM_INCLUDEDIR}) + if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - set(CLAY_CXXFLAGS "${LLVM_CXXFLAGS} -UNDEBUG") + target_compile_definitions(compiler PRIVATE UNDEBUG) + target_compile_definitions(clay PRIVATE UNDEBUG) + target_compile_definitions(claydoc PRIVATE UNDEBUG) + target_compile_definitions(ut PRIVATE UNDEBUG) else() - set(CLAY_CXXFLAGS "${LLVM_CXXFLAGS} -DNDEBUG") + target_compile_definitions(compiler PRIVATE NDEBUG) + target_compile_definitions(clay PRIVATE NDEBUG) + target_compile_definitions(claydoc PRIVATE NDEBUG) + target_compile_definitions(ut PRIVATE NDEBUG) endif() -if (NOT MSVC) - set(CLAY_CXXFLAGS "${CLAY_CXXFLAGS} -fexceptions") + +if(NOT MSVC) + target_compile_options(compiler PRIVATE -fexceptions) + target_compile_options(clay PRIVATE -fexceptions) + target_compile_options(claydoc PRIVATE -fexceptions) + target_compile_options(ut PRIVATE -fexceptions) endif() set(ENABLE_PCH False CACHE BOOL - "Use precompiled headers when building the compiler. (experimental)") + "Use precompiled headers when building the compiler. (experimental)") if(ENABLE_PCH) - precompile_header(clay.hpp SOURCES pch.cpp "${CLAY_CXXFLAGS}") + precompile_header(clay.hpp SOURCES pch.cpp ${LLVM_CXXFLAGS}) endif(ENABLE_PCH) -# Targets -add_library(compiler STATIC ${COMPILER_SOURCES}) -add_executable(clay ${CLAY_SOURCES}) -add_executable(claydoc ${CLAYDOC_SOURCES}) -add_executable(ut ${UT_SOURCES}) - -# compiler flags -target_compile_options(compiler PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(clay PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(claydoc PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(ut PRIVATE "${CLAY_CXXFLAGS}") - if (UNIX) - target_link_options(compiler PRIVATE "${LLVM_LDFLAGS}") - target_link_options(clay PRIVATE "${LLVM_LDFLAGS}") - target_link_options(claydoc PRIVATE "${LLVM_LDFLAGS}") - target_link_options(ut PRIVATE "${LLVM_LDFLAGS}") -endif(UNIX) + target_link_options(compiler PRIVATE ${LLVM_LDFLAGS}) + target_link_options(clay PRIVATE ${LLVM_LDFLAGS}) + target_link_options(claydoc PRIVATE ${LLVM_LDFLAGS}) + target_link_options(ut PRIVATE ${LLVM_LDFLAGS}) +endif() # Libraries target_link_libraries(clay PRIVATE compiler ${LLVM_LIBS}) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index a64b5d81..1c5087c2 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -1,2633 +1,2656 @@ - +#include "analyzer.hpp" +#include "analyzer_op.hpp" #include "clay.hpp" -#include "evaluator.hpp" +#include "clone.hpp" #include "codegen.hpp" -#include "loader.hpp" -#include "operators.hpp" -#include "patterns.hpp" -#include "lambdas.hpp" -#include "analyzer.hpp" -#include "invoketables.hpp" -#include "matchinvoke.hpp" -#include "error.hpp" -#include "literals.hpp" -#include "desugar.hpp" #include "constructors.hpp" +#include "desugar.hpp" #include "env.hpp" -#include "clone.hpp" +#include "error.hpp" +#include "evaluator.hpp" +#include "invoketables.hpp" +#include "lambdas.hpp" +#include "literals.hpp" +#include "loader.hpp" +#include "matchinvoke.hpp" #include "objects.hpp" -#include "analyzer_op.hpp" +#include "operators.hpp" +#include "patterns.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" namespace clay { - GVarInstance::GVarInstance(const GlobalVariablePtr &gvar, - llvm::ArrayRef params) - : gvar(gvar), params(params), - llGlobal(nullptr), debugInfo(nullptr), analyzing(false) { - } +GVarInstance::GVarInstance(const GlobalVariablePtr &gvar, + llvm::ArrayRef params) + : gvar(gvar), params(params), llGlobal(nullptr), debugInfo(nullptr), + analyzing(false) {} - GVarInstance::~GVarInstance() = default; - - Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, bool privateOverload) - : TopLevelItem(PROCEDURE, module, name, visibility), - privateOverload(privateOverload) { - } - - Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, bool privateOverload, - OverloadPtr interface) - : TopLevelItem(PROCEDURE, module, name, visibility), - interface(interface), privateOverload(privateOverload) { - } +GVarInstance::~GVarInstance() = default; - Procedure::~Procedure() { - } +Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, + bool privateOverload) + : TopLevelItem(PROCEDURE, module, name, visibility), + privateOverload(privateOverload) {} - GlobalVariable::GlobalVariable(Module *module, IdentifierPtr name, - Visibility visibility, - llvm::ArrayRef patternVars, - ExprPtr predicate, - llvm::ArrayRef params, - IdentifierPtr varParam, - ExprPtr expr) - : TopLevelItem(GLOBAL_VARIABLE, module, name, visibility), - patternVars(patternVars), predicate(predicate), - params(params), varParam(varParam), expr(expr) { - } +Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, + bool privateOverload, OverloadPtr interface) + : TopLevelItem(PROCEDURE, module, name, visibility), interface(interface), + privateOverload(privateOverload) {} - GlobalVariable::~GlobalVariable() { - } +Procedure::~Procedure() {} - static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, AnalysisContext *ctx); +GlobalVariable::GlobalVariable(Module *module, IdentifierPtr name, + Visibility visibility, + llvm::ArrayRef patternVars, + ExprPtr predicate, + llvm::ArrayRef params, + IdentifierPtr varParam, ExprPtr expr) + : TopLevelItem(GLOBAL_VARIABLE, module, name, visibility), + patternVars(patternVars), predicate(predicate), params(params), + varParam(varParam), expr(expr) {} - static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env); +GlobalVariable::~GlobalVariable() = default; - static int analysisCachingDisabled = 0; - void disableAnalysisCaching() { analysisCachingDisabled += 1; } - void enableAnalysisCaching() { analysisCachingDisabled -= 1; } +static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, + AnalysisContext *ctx); - static TypePtr objectType(ObjectPtr x); +static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env); - static bool staticToTypeTuple(ObjectPtr x, vector &out); +static int analysisCachingDisabled = 0; +void disableAnalysisCaching() { analysisCachingDisabled += 1; } +void enableAnalysisCaching() { analysisCachingDisabled -= 1; } - static void staticToTypeTuple(MultiStaticPtr x, unsigned index, - vector &out); +static TypePtr objectType(ObjectPtr x); - static int staticToInt(MultiStaticPtr x, unsigned index); +static bool staticToTypeTuple(ObjectPtr x, vector &out); - // - // utility procs - // +static void staticToTypeTuple(MultiStaticPtr x, unsigned index, + vector &out); - static TypePtr objectType(ObjectPtr x) { - switch (x->objKind) { - case VALUE_HOLDER: { - ValueHolder *y = (ValueHolder *) x.ptr(); - return y->type; - } +static int staticToInt(MultiStaticPtr x, unsigned index); - case TYPE: - case PRIM_OP: - case PROCEDURE: - case INTRINSIC: - case GLOBAL_ALIAS: - case RECORD_DECL: - case VARIANT_DECL: - case MODULE: - case IDENTIFIER: - return staticType(x); +// +// utility procs +// - default: - error("untypeable object"); - return nullptr; - } +static TypePtr objectType(ObjectPtr x) { + switch (x->objKind) { + case VALUE_HOLDER: { + ValueHolder *y = (ValueHolder *)x.ptr(); + return y->type; } - ObjectPtr unwrapStaticType(TypePtr t) { - if (t->typeKind != STATIC_TYPE) - return nullptr; - StaticType *st = (StaticType *) t.ptr(); - return st->obj; - } + case TYPE: + case PRIM_OP: + case PROCEDURE: + case INTRINSIC: + case GLOBAL_ALIAS: + case RECORD_DECL: + case VARIANT_DECL: + case MODULE: + case IDENTIFIER: + return staticType(x); - static bool staticToTypeTuple(ObjectPtr x, vector &out) { - TypePtr t; - if (staticToType(x, t)) { - out.push_back(t); - return true; - } - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr y = (ValueHolder *) x.ptr(); - assert(y->type->typeKind != STATIC_TYPE); - if (y->type->typeKind != TUPLE_TYPE) - return false; - TupleTypePtr z = static_cast(y->type.ptr()); - for (const auto &elementType: z->elementTypes) { - ObjectPtr obj = unwrapStaticType(elementType); - if ((!obj) || (obj->objKind != TYPE)) - return false; - out.push_back(static_cast(obj.ptr())); - } - return true; + default: + error("untypeable object"); + return nullptr; } +} - static void staticToTypeTuple(MultiStaticPtr x, const unsigned index, - vector &out) { - if (!staticToTypeTuple(x->values[index], out)) - argumentError(index, "expecting zero-or-more types"); - } +ObjectPtr unwrapStaticType(TypePtr t) { + if (t->typeKind != STATIC_TYPE) + return nullptr; + StaticType *st = (StaticType *)t.ptr(); + return st->obj; +} - static bool staticToInt(ObjectPtr x, int &out, TypePtr &type) { - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr vh = static_cast(x.ptr()); - if (vh->type != cIntType) { - type = vh->type; - return false; - } - out = vh->as(); +static bool staticToTypeTuple(ObjectPtr x, vector &out) { + TypePtr t; + if (staticToType(x, t)) { + out.push_back(t); return true; } - - static int staticToInt(MultiStaticPtr x, unsigned index) { - int out = -1; - TypePtr type; - if (!staticToInt(x->values[index], out, type)) { - argumentTypeError(index, "Int", type); - } - return out; - } - - bool staticToBool(ObjectPtr x, bool &out, TypePtr &type) { - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr vh = (ValueHolder *) x.ptr(); - if (vh->type != boolType) { - type = vh->type; + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr y = (ValueHolder *)x.ptr(); + assert(y->type->typeKind != STATIC_TYPE); + if (y->type->typeKind != TUPLE_TYPE) + return false; + TupleTypePtr z = static_cast(y->type.ptr()); + for (const auto &elementType : z->elementTypes) { + ObjectPtr obj = unwrapStaticType(elementType); + if ((!obj) || (obj->objKind != TYPE)) return false; - } - out = vh->as(); - return true; + out.push_back(static_cast(obj.ptr())); } + return true; +} - bool staticToBool(MultiStaticPtr x, unsigned index) { - bool out = false; - TypePtr type; - if (!staticToBool(x->values[index], out, type)) - argumentTypeError(index, "Bool", type); - return out; - } +static void staticToTypeTuple(MultiStaticPtr x, const unsigned index, + vector &out) { + if (!staticToTypeTuple(x->values[index], out)) + argumentError(index, "expecting zero-or-more types"); +} - bool staticToCallingConv(ObjectPtr x, CallingConv &out) { - if (x->objKind != PRIM_OP) - return false; - PrimOp *ccPrim = (PrimOp *) x.ptr(); - switch (ccPrim->primOpCode) { - case PRIM_AttributeCCall: - out = CC_DEFAULT; - return true; - case PRIM_AttributeStdCall: - out = CC_STDCALL; - return true; - case PRIM_AttributeFastCall: - out = CC_FASTCALL; - return true; - case PRIM_AttributeThisCall: - out = CC_THISCALL; - return true; - case PRIM_AttributeLLVMCall: - out = CC_LLVM; - return true; - default: - return false; - } +static bool staticToInt(ObjectPtr x, int &out, TypePtr &type) { + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr vh = static_cast(x.ptr()); + if (vh->type != cIntType) { + type = vh->type; + return false; } + out = vh->as(); + return true; +} - CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index) { - CallingConv out; - if (!staticToCallingConv(x->values[index], out)) - argumentError(index, "expecting calling convention attribute"); - return out; +static int staticToInt(MultiStaticPtr x, unsigned index) { + int out = -1; + TypePtr type; + if (!staticToInt(x->values[index], out, type)) { + argumentTypeError(index, "Int", type); } + return out; +} - // - // safe analysis - // +bool staticToBool(ObjectPtr x, bool &out, TypePtr &type) { + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr vh = (ValueHolder *)x.ptr(); + if (vh->type != boolType) { + type = vh->type; + return false; + } + out = vh->as(); + return true; +} - static Location analysisErrorLocation; - static vector analysisErrorCompileContext; +bool staticToBool(MultiStaticPtr x, unsigned index) { + bool out = false; + TypePtr type; + if (!staticToBool(x->values[index], out, type)) + argumentTypeError(index, "Bool", type); + return out; +} - struct ClearAnalysisError { - ClearAnalysisError() { - } +bool staticToCallingConv(ObjectPtr x, CallingConv &out) { + if (x->objKind != PRIM_OP) + return false; + PrimOp *ccPrim = (PrimOp *)x.ptr(); + switch (ccPrim->primOpCode) { + case PRIM_AttributeCCall: + out = CC_DEFAULT; + return true; + case PRIM_AttributeStdCall: + out = CC_STDCALL; + return true; + case PRIM_AttributeFastCall: + out = CC_FASTCALL; + return true; + case PRIM_AttributeThisCall: + out = CC_THISCALL; + return true; + case PRIM_AttributeLLVMCall: + out = CC_LLVM; + return true; + default: + return false; + } +} - ~ClearAnalysisError() { - analysisErrorLocation = Location(); - analysisErrorCompileContext.clear(); - } - }; +CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index) { + CallingConv out; + if (!staticToCallingConv(x->values[index], out)) + argumentError(index, "expecting calling convention attribute"); + return out; +} - static void updateAnalysisErrorLocation() { - analysisErrorLocation = topLocation(); - analysisErrorCompileContext = getCompileContext(); - } +// +// safe analysis +// - static void analysisError() { - setCompileContext(analysisErrorCompileContext); - LocationContext loc(analysisErrorLocation); - error("type propagation failed due to recursion without base case"); - } +static Location analysisErrorLocation; +static vector analysisErrorCompileContext; - PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env) { - ClearAnalysisError clear; - PVData result = analyzeOne(expr, env); - if (!result.ok()) - analysisError(); - return result; - } +struct ClearAnalysisError { + ClearAnalysisError() = default; - MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeMulti(exprs, env, wantCount); - if (!result) - analysisError(); - return result; + ~ClearAnalysisError() { + analysisErrorLocation = Location(); + analysisErrorCompileContext.clear(); } +}; - MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeExpr(expr, env); - if (!result) - analysisError(); - return result; - } +static void updateAnalysisErrorLocation() { + analysisErrorLocation = topLocation(); + analysisErrorCompileContext = getCompileContext(); +} - MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeIndexingExpr(indexable, args, env); - if (!result) - analysisError(); - return result; - } +static void analysisError() { + setCompileContext(analysisErrorCompileContext); + LocationContext loc(analysisErrorLocation); + error("type propagation failed due to recursion without base case"); +} - MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeMultiArgs(exprs, env, dispatchIndices); - if (!result) - analysisError(); - return result; - } - - InvokeEntry *safeAnalyzeCallable(ObjectPtr x, - llvm::ArrayRef args) { - ClearAnalysisError clear; - InvokeEntry *entry = analyzeCallable(x, args); - if (!entry->callByName && !entry->analyzed) - analysisError(); - return entry; - } +PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env) { + ClearAnalysisError clear; + PVData result = analyzeOne(expr, env); + if (!result.ok()) + analysisError(); + return result; +} - MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeCallByName(entry, callable, args, env); - if (!entry) - analysisError(); - return result; - } +MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, + size_t wantCount) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeMulti(exprs, env, wantCount); + if (!result) + analysisError(); + return result; +} - MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeGVarInstance(x); - if (!result) - analysisError(); - return result; - } +MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeExpr(expr, env); + if (!result) + analysisError(); + return result; +} - // - // analyzeMulti - // +MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, + EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeIndexingExpr(indexable, args, env); + if (!result) + analysisError(); + return result; +} - static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, size_t wantCount); +MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeMultiArgs(exprs, env, dispatchIndices); + if (!result) + analysisError(); + return result; +} - MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - if (analysisCachingDisabled > 0) - return analyzeMulti2(exprs, env, wantCount); - if (!exprs->cachedAnalysis) - exprs->cachedAnalysis = analyzeMulti2(exprs, env, wantCount); - return exprs->cachedAnalysis; - } +InvokeEntry *safeAnalyzeCallable(ObjectPtr x, llvm::ArrayRef args) { + ClearAnalysisError clear; + InvokeEntry *entry = analyzeCallable(x, args); + if (!entry->callByName && !entry->analyzed) + analysisError(); + return entry; +} - static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - MultiPValuePtr out = new MultiPValue(); - ExprPtr unpackExpr = implicitUnpackExpr(wantCount, exprs); - if (unpackExpr != nullptr) { - MultiPValuePtr z = analyzeExpr(unpackExpr, env); - if (!z) - return nullptr; - out->add(z); - } else - for (unsigned i = 0; i < exprs->size(); ++i) { - ExprPtr x = exprs->exprs[i]; - if (x->exprKind == UNPACK) { - Unpack *y = (Unpack *) x.ptr(); - MultiPValuePtr z = analyzeExpr(y->expr, env); - if (!z) - return nullptr; - out->add(z); - } else if (x->exprKind == PAREN) { - MultiPValuePtr y = analyzeExpr(x, env); - if (!y) - return nullptr; - out->add(y); - } else { - PVData y = analyzeOne(x, env); - if (!y.ok()) - return nullptr; - out->add(y); - } - } - return out; - } +MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeCallByName(entry, callable, args, env); + if (!entry) + analysisError(); + return result; +} - // - // analyzeOne - // +MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeGVarInstance(x); + if (!result) + analysisError(); + return result; +} - PVData analyzeOne(ExprPtr expr, EnvPtr env) { - MultiPValuePtr x = analyzeExpr(expr, env); - if (!x) - return PVData(); - LocationContext loc(expr->location); - ensureArity(x, 1); - return x->values[0]; - } +// +// analyzeMulti +// - // - // analyzeMultiArgs, analyzeOneArg, analyzeArgExpr - // +static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, + size_t wantCount); - static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); +MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { + if (analysisCachingDisabled > 0) + return analyzeMulti2(exprs, env, wantCount); + if (!exprs->cachedAnalysis) + exprs->cachedAnalysis = analyzeMulti2(exprs, env, wantCount); + return exprs->cachedAnalysis; +} - MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices) { - if (analysisCachingDisabled > 0) - return analyzeMultiArgs2(exprs, env, 0, dispatchIndices); - if (!exprs->cachedAnalysis) { - MultiPValuePtr mpv = analyzeMultiArgs2(exprs, env, 0, dispatchIndices); - if (mpv.ptr() && dispatchIndices.empty()) - exprs->cachedAnalysis = mpv; - return mpv; - } - return exprs->cachedAnalysis; - } - - static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - MultiPValuePtr out = new MultiPValue(); - unsigned index = startIndex; +static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, + size_t wantCount) { + MultiPValuePtr out = new MultiPValue(); + ExprPtr unpackExpr = implicitUnpackExpr(wantCount, exprs); + if (unpackExpr != nullptr) { + MultiPValuePtr z = analyzeExpr(unpackExpr, env); + if (!z) + return nullptr; + out->add(z); + } else for (unsigned i = 0; i < exprs->size(); ++i) { ExprPtr x = exprs->exprs[i]; if (x->exprKind == UNPACK) { - Unpack *y = (Unpack *) x.ptr(); - MultiPValuePtr z = analyzeArgExpr(y->expr, env, index, dispatchIndices); + Unpack *y = (Unpack *)x.ptr(); + MultiPValuePtr z = analyzeExpr(y->expr, env); if (!z) return nullptr; - index += unsigned(z->size()); out->add(z); } else if (x->exprKind == PAREN) { - MultiPValuePtr z = analyzeArgExpr(x, env, index, dispatchIndices); - if (!z) + MultiPValuePtr y = analyzeExpr(x, env); + if (!y) return nullptr; - index += unsigned(z->size()); - out->add(z); + out->add(y); } else { - PVData y = analyzeOneArg(x, env, index, dispatchIndices); + PVData y = analyzeOne(x, env); if (!y.ok()) return nullptr; out->add(y); - index += 1; } } - return out; - } + return out; +} - PVData analyzeOneArg(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - MultiPValuePtr mpv = analyzeArgExpr(x, env, startIndex, dispatchIndices); - if (!mpv) - return PVData(); - LocationContext loc(x->location); - ensureArity(mpv, 1); - return mpv->values[0]; - } - - MultiPValuePtr analyzeArgExpr(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - if (x->exprKind == DISPATCH_EXPR) { - DispatchExpr *y = (DispatchExpr *) x.ptr(); - MultiPValuePtr mpv = analyzeExpr(y->expr, env); - if (!mpv) - return nullptr; - for (unsigned i = 0; i < mpv->size(); ++i) - dispatchIndices.push_back(i + startIndex); - return mpv; - } - return analyzeExpr(x, env); - } - - // - // analyzeExpr - // - - static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env); - - void appendArgString(Expr *expr, string *outString) { - ForeignExpr *fexpr; - if (expr->exprKind == FOREIGN_EXPR) - fexpr = (ForeignExpr *) expr; - else if (expr->exprKind == UNPACK) { - Unpack *uexpr = (Unpack *) expr; - if (uexpr->expr->exprKind != FOREIGN_EXPR) - goto notAlias; - fexpr = (ForeignExpr *) uexpr->expr.ptr(); - *outString += ".."; - } else - goto notAlias; +// +// analyzeOne +// + +PVData analyzeOne(ExprPtr expr, EnvPtr env) { + MultiPValuePtr x = analyzeExpr(expr, env); + if (!x) + return PVData(); + LocationContext loc(expr->location); + ensureArity(x, 1); + return x->values[0]; +} - *outString += fexpr->expr->asString(); - return; +// +// analyzeMultiArgs, analyzeOneArg, analyzeArgExpr +// + +static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, EnvPtr env, + unsigned startIndex, + vector &dispatchIndices); + +MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices) { + if (analysisCachingDisabled > 0) + return analyzeMultiArgs2(exprs, env, 0, dispatchIndices); + if (!exprs->cachedAnalysis) { + MultiPValuePtr mpv = analyzeMultiArgs2(exprs, env, 0, dispatchIndices); + if (mpv.ptr() && dispatchIndices.empty()) + exprs->cachedAnalysis = mpv; + return mpv; + } + return exprs->cachedAnalysis; +} - notAlias: - error("__ARG__ may only be applied to an alias value or alias function argument"); +static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, EnvPtr env, + unsigned startIndex, + vector &dispatchIndices) { + MultiPValuePtr out = new MultiPValue(); + unsigned index = startIndex; + for (unsigned i = 0; i < exprs->size(); ++i) { + ExprPtr x = exprs->exprs[i]; + if (x->exprKind == UNPACK) { + Unpack *y = (Unpack *)x.ptr(); + MultiPValuePtr z = + analyzeArgExpr(y->expr, env, index, dispatchIndices); + if (!z) + return nullptr; + index += unsigned(z->size()); + out->add(z); + } else if (x->exprKind == PAREN) { + MultiPValuePtr z = analyzeArgExpr(x, env, index, dispatchIndices); + if (!z) + return nullptr; + index += unsigned(z->size()); + out->add(z); + } else { + PVData y = analyzeOneArg(x, env, index, dispatchIndices); + if (!y.ok()) + return nullptr; + out->add(y); + index += 1; + } } + return out; +} + +PVData analyzeOneArg(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices) { + MultiPValuePtr mpv = analyzeArgExpr(x, env, startIndex, dispatchIndices); + if (!mpv) + return PVData(); + LocationContext loc(x->location); + ensureArity(mpv, 1); + return mpv->values[0]; +} - MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env) { - if (analysisCachingDisabled > 0) - return analyzeExpr2(expr, env); - if (!expr->cachedAnalysis) - expr->cachedAnalysis = analyzeExpr2(expr, env); - return expr->cachedAnalysis; +MultiPValuePtr analyzeArgExpr(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices) { + if (x->exprKind == DISPATCH_EXPR) { + DispatchExpr *y = (DispatchExpr *)x.ptr(); + MultiPValuePtr mpv = analyzeExpr(y->expr, env); + if (!mpv) + return nullptr; + for (unsigned i = 0; i < mpv->size(); ++i) + dispatchIndices.push_back(i + startIndex); + return mpv; } + return analyzeExpr(x, env); +} - static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env) { - LocationContext loc(expr->location); - switch (expr->exprKind) { - case BOOL_LITERAL: { - return new MultiPValue(PVData(boolType, true)); - } +// +// analyzeExpr +// - case INT_LITERAL: { - IntLiteral *x = (IntLiteral *) expr.ptr(); - ValueHolderPtr v = parseIntLiteral(safeLookupModule(env), x); - return new MultiPValue(PVData(v->type, true)); - } +static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env); - case FLOAT_LITERAL: { - FloatLiteral *x = (FloatLiteral *) expr.ptr(); - ValueHolderPtr v = parseFloatLiteral(safeLookupModule(env), x); - return new MultiPValue(PVData(v->type, true)); - } +void appendArgString(Expr *expr, string *outString) { + ForeignExpr *fexpr; + if (expr->exprKind == FOREIGN_EXPR) + fexpr = (ForeignExpr *)expr; + else if (expr->exprKind == UNPACK) { + Unpack *uexpr = (Unpack *)expr; + if (uexpr->expr->exprKind != FOREIGN_EXPR) + goto notAlias; + fexpr = (ForeignExpr *)uexpr->expr.ptr(); + *outString += ".."; + } else + goto notAlias; - case CHAR_LITERAL: { - CharLiteral *x = (CharLiteral *) expr.ptr(); - if (!x->desugared) - x->desugared = desugarCharLiteral(x->value); - return analyzeExpr(x->desugared, env); - } + *outString += fexpr->expr->asString(); + return; - case STRING_LITERAL: { - StringLiteral *x = (StringLiteral *) expr.ptr(); - return new MultiPValue(staticPValue(x->value.ptr())); - } +notAlias: + error("__ARG__ may only be applied to an alias value or alias function " + "argument"); +} - case NAME_REF: { - NameRef *x = (NameRef *) expr.ptr(); - ObjectPtr y = safeLookupEnv(env, x->name); - if (y->objKind == EXPRESSION) { - ExprPtr z = (Expr *) y.ptr(); - return analyzeExpr(z, env); - } else if (y->objKind == EXPR_LIST) { - ExprListPtr z = (ExprList *) y.ptr(); - return analyzeMulti(z, env, 0); - } - return analyzeStaticObject(y); - } +MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env) { + if (analysisCachingDisabled > 0) + return analyzeExpr2(expr, env); + if (!expr->cachedAnalysis) + expr->cachedAnalysis = analyzeExpr2(expr, env); + return expr->cachedAnalysis; +} - case FILE_EXPR: { - Location location = safeLookupCallByNameLocation(env); - string filename = location.source->fileName; - return analyzeStaticObject(Identifier::get(filename)); - } +static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env) { + LocationContext loc(expr->location); + switch (expr->exprKind) { + case BOOL_LITERAL: { + return new MultiPValue(PVData(boolType, true)); + } - case LINE_EXPR: { - return new MultiPValue(PVData(cSizeTType, true)); - } + case INT_LITERAL: { + IntLiteral *x = (IntLiteral *)expr.ptr(); + ValueHolderPtr v = parseIntLiteral(safeLookupModule(env), x); + return new MultiPValue(PVData(v->type, true)); + } - case COLUMN_EXPR: { - return new MultiPValue(PVData(cSizeTType, true)); - } + case FLOAT_LITERAL: { + FloatLiteral *x = (FloatLiteral *)expr.ptr(); + ValueHolderPtr v = parseFloatLiteral(safeLookupModule(env), x); + return new MultiPValue(PVData(v->type, true)); + } - case ARG_EXPR: { - ARGExpr *arg = (ARGExpr *) expr.ptr(); - ObjectPtr obj = safeLookupEnv(env, arg->name); - string argString; - if (obj->objKind == EXPRESSION) { - Expr *expr = (Expr *) obj.ptr(); - appendArgString(expr, &argString); - } else if (obj->objKind == EXPR_LIST) { - ExprList *elist = (ExprList *) obj.ptr(); - for (vector::const_iterator i = elist->exprs.begin(), - end = elist->exprs.end(); - i != end; - ++i) { - if (!argString.empty()) - argString += ", "; - - Expr *expr = i->ptr(); - appendArgString(expr, &argString); - } - } - return analyzeStaticObject(Identifier::get(argString)); - } + case CHAR_LITERAL: { + CharLiteral *x = (CharLiteral *)expr.ptr(); + if (!x->desugared) + x->desugared = desugarCharLiteral(x->value); + return analyzeExpr(x->desugared, env); + } - case TUPLE: { - Tuple *x = (Tuple *) expr.ptr(); - return analyzeCallExpr(operator_expr_tupleLiteral(), - x->args, - env); - } + case STRING_LITERAL: { + StringLiteral *x = (StringLiteral *)expr.ptr(); + return new MultiPValue(staticPValue(x->value.ptr())); + } - case PAREN: { - Paren *x = (Paren *) expr.ptr(); - return analyzeMulti(x->args, env, 0); - } + case NAME_REF: { + NameRef *x = (NameRef *)expr.ptr(); + ObjectPtr y = safeLookupEnv(env, x->name); + if (y->objKind == EXPRESSION) { + ExprPtr z = (Expr *)y.ptr(); + return analyzeExpr(z, env); + } else if (y->objKind == EXPR_LIST) { + ExprListPtr z = (ExprList *)y.ptr(); + return analyzeMulti(z, env, 0); + } + return analyzeStaticObject(y); + } - case INDEXING: { - Indexing *x = (Indexing *) expr.ptr(); - return analyzeIndexingExpr(x->expr, x->args, env); - } + case FILE_EXPR: { + Location location = safeLookupCallByNameLocation(env); + string filename = location.source->fileName; + return analyzeStaticObject(Identifier::get(filename)); + } - case CALL: { - Call *x = (Call *) expr.ptr(); - return analyzeCallExpr(x->expr, x->allArgs(), env); - } + case LINE_EXPR: { + return new MultiPValue(PVData(cSizeTType, true)); + } - case FIELD_REF: { - FieldRef *x = (FieldRef *) expr.ptr(); - if (!x->desugared) - desugarFieldRef(x, safeLookupModule(env)); - if (x->isDottedModuleName) - return analyzeExpr(x->desugared, env); + case COLUMN_EXPR: { + return new MultiPValue(PVData(cSizeTType, true)); + } - PVData pv = analyzeOne(x->expr, env); - if (!pv.ok()) - return nullptr; - if (pv.type->typeKind == STATIC_TYPE) { - StaticType *st = (StaticType *) pv.type.ptr(); - if (st->obj->objKind == MODULE) { - Module *m = (Module *) st->obj.ptr(); - ObjectPtr obj = safeLookupPublic(m, x->name); - return analyzeStaticObject(obj); - } - } + case ARG_EXPR: { + ARGExpr *arg = (ARGExpr *)expr.ptr(); + ObjectPtr obj = safeLookupEnv(env, arg->name); + string argString; + if (obj->objKind == EXPRESSION) { + Expr *expr = (Expr *)obj.ptr(); + appendArgString(expr, &argString); + } else if (obj->objKind == EXPR_LIST) { + ExprList *elist = (ExprList *)obj.ptr(); + for (vector::const_iterator i = elist->exprs.begin(), + end = elist->exprs.end(); + i != end; ++i) { + if (!argString.empty()) + argString += ", "; - return analyzeExpr(x->desugared, env); + Expr *expr = i->ptr(); + appendArgString(expr, &argString); } + } + return analyzeStaticObject(Identifier::get(argString)); + } - case STATIC_INDEXING: { - StaticIndexing *x = (StaticIndexing *) expr.ptr(); - if (!x->desugared) - x->desugared = desugarStaticIndexing(x); - return analyzeExpr(x->desugared, env); - } + case TUPLE: { + Tuple *x = (Tuple *)expr.ptr(); + return analyzeCallExpr(operator_expr_tupleLiteral(), x->args, env); + } - case VARIADIC_OP: { - VariadicOp *x = (VariadicOp *) expr.ptr(); - if (x->op == ADDRESS_OF) { - PVData pv = analyzeOne(x->exprs->exprs.front(), env); - if (!pv.ok()) - return nullptr; - if (pv.isRValue) - error("can't take address of a temporary"); - } - if (!x->desugared) - x->desugared = desugarVariadicOp(x); - return analyzeExpr(x->desugared, env); - } + case PAREN: { + Paren *x = (Paren *)expr.ptr(); + return analyzeMulti(x->args, env, 0); + } - case EVAL_EXPR: { - EvalExpr *eval = (EvalExpr *) expr.ptr(); - // XXX compilation context - ExprListPtr evaled = desugarEvalExpr(eval, env); - return analyzeMulti(evaled, env, 0); - } + case INDEXING: { + Indexing *x = (Indexing *)expr.ptr(); + return analyzeIndexingExpr(x->expr, x->args, env); + } - case AND: { - return new MultiPValue(PVData(boolType, true)); - } + case CALL: { + Call *x = (Call *)expr.ptr(); + return analyzeCallExpr(x->expr, x->allArgs(), env); + } - case OR: { - return new MultiPValue(PVData(boolType, true)); - } + case FIELD_REF: { + FieldRef *x = (FieldRef *)expr.ptr(); + if (!x->desugared) + desugarFieldRef(x, safeLookupModule(env)); + if (x->isDottedModuleName) + return analyzeExpr(x->desugared, env); - case LAMBDA: { - Lambda *x = (Lambda *) expr.ptr(); - if (!x->initialized) - initializeLambda(x, env); - return analyzeExpr(x->converted, env); + PVData pv = analyzeOne(x->expr, env); + if (!pv.ok()) + return nullptr; + if (pv.type->typeKind == STATIC_TYPE) { + StaticType *st = (StaticType *)pv.type.ptr(); + if (st->obj->objKind == MODULE) { + Module *m = (Module *)st->obj.ptr(); + ObjectPtr obj = safeLookupPublic(m, x->name); + return analyzeStaticObject(obj); } + } - case UNPACK: { - Unpack *unpack = (Unpack *) expr.ptr(); - if (unpack->expr->exprKind != FOREIGN_EXPR) - error("incorrect usage of unpack operator"); - return analyzeExpr(unpack->expr, env); - } + return analyzeExpr(x->desugared, env); + } - case STATIC_EXPR: { - StaticExpr *x = (StaticExpr *) expr.ptr(); - ObjectPtr obj = evaluateOneStatic(x->expr, env); - TypePtr t = staticType(obj); - return new MultiPValue(PVData(t, true)); - } + case STATIC_INDEXING: { + StaticIndexing *x = (StaticIndexing *)expr.ptr(); + if (!x->desugared) + x->desugared = desugarStaticIndexing(x); + return analyzeExpr(x->desugared, env); + } - case DISPATCH_EXPR: { - error("incorrect usage of dispatch operator"); + case VARIADIC_OP: { + VariadicOp *x = (VariadicOp *)expr.ptr(); + if (x->op == ADDRESS_OF) { + PVData pv = analyzeOne(x->exprs->exprs.front(), env); + if (!pv.ok()) return nullptr; - } + if (pv.isRValue) + error("can't take address of a temporary"); + } + if (!x->desugared) + x->desugared = desugarVariadicOp(x); + return analyzeExpr(x->desugared, env); + } - case FOREIGN_EXPR: { - ForeignExpr *x = (ForeignExpr *) expr.ptr(); - return analyzeExpr(x->expr, x->getEnv()); - } + case EVAL_EXPR: { + EvalExpr *eval = (EvalExpr *)expr.ptr(); + // XXX compilation context + ExprListPtr evaled = desugarEvalExpr(eval, env); + return analyzeMulti(evaled, env, 0); + } - case OBJECT_EXPR: { - ObjectExpr *x = (ObjectExpr *) expr.ptr(); - return analyzeStaticObject(x->obj); - } + case AND: { + return new MultiPValue(PVData(boolType, true)); + } - default: - assert(false); - return nullptr; - } + case OR: { + return new MultiPValue(PVData(boolType, true)); } - // - // analyzeStaticObject - // + case LAMBDA: { + Lambda *x = (Lambda *)expr.ptr(); + if (!x->initialized) + initializeLambda(x, env); + return analyzeExpr(x->converted, env); + } - MultiPValuePtr analyzeStaticObject(ObjectPtr x) { - switch (x->objKind) { - case NEW_TYPE_DECL: { - NewTypeDecl *y = (NewTypeDecl *) x.ptr(); - assert(y->type->typeKind == NEW_TYPE); - initializeNewType(y->type); + case UNPACK: { + Unpack *unpack = (Unpack *)expr.ptr(); + if (unpack->expr->exprKind != FOREIGN_EXPR) + error("incorrect usage of unpack operator"); + return analyzeExpr(unpack->expr, env); + } - return new MultiPValue(PVData(y->type.ptr(), true)); - } + case STATIC_EXPR: { + StaticExpr *x = (StaticExpr *)expr.ptr(); + ObjectPtr obj = evaluateOneStatic(x->expr, env); + TypePtr t = staticType(obj); + return new MultiPValue(PVData(t, true)); + } - case ENUM_MEMBER: { - EnumMember *y = (EnumMember *) x.ptr(); - assert(y->type->typeKind == ENUM_TYPE); - initializeEnumType((EnumType *) y->type.ptr()); + case DISPATCH_EXPR: { + error("incorrect usage of dispatch operator"); + return nullptr; + } - return new MultiPValue(PVData(y->type, true)); - } + case FOREIGN_EXPR: { + ForeignExpr *x = (ForeignExpr *)expr.ptr(); + return analyzeExpr(x->expr, x->getEnv()); + } - case GLOBAL_VARIABLE: { - GlobalVariable *y = (GlobalVariable *) x.ptr(); - if (y->hasParams()) { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } - GVarInstancePtr inst = defaultGVarInstance(y); - return analyzeGVarInstance(inst); - } + case OBJECT_EXPR: { + ObjectExpr *x = (ObjectExpr *)expr.ptr(); + return analyzeStaticObject(x->obj); + } - case EXTERNAL_VARIABLE: { - ExternalVariable *y = (ExternalVariable *) x.ptr(); - return new MultiPValue(analyzeExternalVariable(y)); - } + default: + assert(false); + return nullptr; + } +} - case EXTERNAL_PROCEDURE: { - ExternalProcedure *y = (ExternalProcedure *) x.ptr(); - analyzeExternalProcedure(y); - return new MultiPValue(PVData(y->ptrType, true)); - } +// +// analyzeStaticObject +// - case GLOBAL_ALIAS: { - GlobalAlias *y = (GlobalAlias *) x.ptr(); - if (y->hasParams()) { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } - evaluatePredicate(y->patternVars, y->predicate, y->env); - return analyzeExpr(y->expr, y->env); - } +MultiPValuePtr analyzeStaticObject(ObjectPtr x) { + switch (x->objKind) { + case NEW_TYPE_DECL: { + NewTypeDecl *y = (NewTypeDecl *)x.ptr(); + assert(y->type->typeKind == NEW_TYPE); + initializeNewType(y->type); - case VALUE_HOLDER: { - ValueHolder *y = (ValueHolder *) x.ptr(); - return new MultiPValue(PVData(y->type, true)); - } + return new MultiPValue(PVData(y->type.ptr(), true)); + } - case MULTI_STATIC: { - MultiStatic *y = (MultiStatic *) x.ptr(); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < y->size(); ++i) { - TypePtr t = objectType(y->values[i]); - mpv->values.push_back(PVData(t, true)); - } - return mpv; - } + case ENUM_MEMBER: { + EnumMember *y = (EnumMember *)x.ptr(); + assert(y->type->typeKind == ENUM_TYPE); + initializeEnumType((EnumType *)y->type.ptr()); - case RECORD_DECL: { - RecordDecl *y = (RecordDecl *) x.ptr(); - ObjectPtr z; - if (y->params.empty() && !y->varParam) - z = recordType(y, vector()).ptr(); - else - z = y; - return new MultiPValue(PVData(staticType(z), true)); - } + return new MultiPValue(PVData(y->type, true)); + } - case VARIANT_DECL: { - VariantDecl *y = (VariantDecl *) x.ptr(); - ObjectPtr z; - if (y->params.empty() && !y->varParam) - z = variantType(y, vector()).ptr(); - else - z = y; - return new MultiPValue(PVData(staticType(z), true)); - } + case GLOBAL_VARIABLE: { + GlobalVariable *y = (GlobalVariable *)x.ptr(); + if (y->hasParams()) { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); + } + GVarInstancePtr inst = defaultGVarInstance(y); + return analyzeGVarInstance(inst); + } - case TYPE: - case PRIM_OP: - case PROCEDURE: - case MODULE: - case INTRINSIC: - case IDENTIFIER: { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } + case EXTERNAL_VARIABLE: { + ExternalVariable *y = (ExternalVariable *)x.ptr(); + return new MultiPValue(analyzeExternalVariable(y)); + } - case EVALUE: { - EValue *y = (EValue *) x.ptr(); - return new MultiPValue(PVData(y->type, y->forwardedRValue)); - } + case EXTERNAL_PROCEDURE: { + ExternalProcedure *y = (ExternalProcedure *)x.ptr(); + analyzeExternalProcedure(y); + return new MultiPValue(PVData(y->ptrType, true)); + } - case MULTI_EVALUE: { - MultiEValue *y = (MultiEValue *) x.ptr(); - MultiPValuePtr z = new MultiPValue(); - for (size_t i = 0; i < y->values.size(); ++i) { - EValue *ev = y->values[i].ptr(); - z->values.push_back(PVData(ev->type, ev->forwardedRValue)); - } - return z; - } + case GLOBAL_ALIAS: { + GlobalAlias *y = (GlobalAlias *)x.ptr(); + if (y->hasParams()) { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); + } + evaluatePredicate(y->patternVars, y->predicate, y->env); + return analyzeExpr(y->expr, y->env); + } - case CVALUE: { - CValue *y = (CValue *) x.ptr(); - return new MultiPValue(PVData(y->type, y->forwardedRValue)); - } + case VALUE_HOLDER: { + ValueHolder *y = (ValueHolder *)x.ptr(); + return new MultiPValue(PVData(y->type, true)); + } - case MULTI_CVALUE: { - MultiCValue *y = (MultiCValue *) x.ptr(); - MultiPValuePtr z = new MultiPValue(); - for (size_t i = 0; i < y->values.size(); ++i) { - CValue *cv = y->values[i].ptr(); - z->add(PVData(cv->type, cv->forwardedRValue)); - } - return z; - } + case MULTI_STATIC: { + MultiStatic *y = (MultiStatic *)x.ptr(); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < y->size(); ++i) { + TypePtr t = objectType(y->values[i]); + mpv->values.push_back(PVData(t, true)); + } + return mpv; + } - case PVALUE: { - PValue *y = (PValue *) x.ptr(); - return new MultiPValue(y->data); - } + case RECORD_DECL: { + RecordDecl *y = (RecordDecl *)x.ptr(); + ObjectPtr z; + if (y->params.empty() && !y->varParam) + z = recordType(y, vector()).ptr(); + else + z = y; + return new MultiPValue(PVData(staticType(z), true)); + } - case MULTI_PVALUE: { - MultiPValue *y = (MultiPValue *) x.ptr(); - return y; - } - - case PATTERN: - case MULTI_PATTERN: - error("pattern variable cannot be used as value"); - return nullptr; + case VARIANT_DECL: { + VariantDecl *y = (VariantDecl *)x.ptr(); + ObjectPtr z; + if (y->params.empty() && !y->varParam) + z = variantType(y, vector()).ptr(); + else + z = y; + return new MultiPValue(PVData(staticType(z), true)); + } - default: - invalidStaticObjectError(x); - return nullptr; - } + case TYPE: + case PRIM_OP: + case PROCEDURE: + case MODULE: + case INTRINSIC: + case IDENTIFIER: { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); } - // - // lookupGVarInstance, defaultGVarInstance - // analyzeGVarIndexing, analyzeGVarInstance - // + case EVALUE: { + EValue *y = (EValue *)x.ptr(); + return new MultiPValue(PVData(y->type, y->forwardedRValue)); + } - GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, - llvm::ArrayRef params) { - if (!x->instances) - x->instances = new ObjectTable(); - Pointer &y = x->instances->lookup(params); - if (!y) { - y = new GVarInstance(x, params); + case MULTI_EVALUE: { + MultiEValue *y = (MultiEValue *)x.ptr(); + MultiPValuePtr z = new MultiPValue(); + for (size_t i = 0; i < y->values.size(); ++i) { + EValue *ev = y->values[i].ptr(); + z->values.push_back(PVData(ev->type, ev->forwardedRValue)); } - return (GVarInstance *) y.ptr(); + return z; } - GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x) { - return lookupGVarInstance(x, vector()); + case CVALUE: { + CValue *y = (CValue *)x.ptr(); + return new MultiPValue(PVData(y->type, y->forwardedRValue)); } - GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, - ExprListPtr args, - EnvPtr env) { - assert(x->hasParams()); - MultiStaticPtr params = evaluateMultiStatic(args, env); - if (x->varParam.ptr()) { - if (params->size() < x->params.size()) - arityError2(x->params.size(), params->size()); - } else { - ensureArity(params, x->params.size()); + case MULTI_CVALUE: { + MultiCValue *y = (MultiCValue *)x.ptr(); + MultiPValuePtr z = new MultiPValue(); + for (size_t i = 0; i < y->values.size(); ++i) { + CValue *cv = y->values[i].ptr(); + z->add(PVData(cv->type, cv->forwardedRValue)); } - return lookupGVarInstance(x, params->values); + return z; } - MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x) { - if (x->analysis.ptr()) - return x->analysis; - CompileContextPusher pusher(x->gvar.ptr(), x->params); - if (x->analyzing) { - updateAnalysisErrorLocation(); - return nullptr; - } - GlobalVariablePtr gvar = x->gvar; - if (!x->expr) - x->expr = clone(gvar->expr); - if (!x->env) { - x->env = new Env(gvar->env); - for (size_t i = 0; i < gvar->params.size(); ++i) { - addLocal(x->env, gvar->params[i], x->params[i]); - } - if (gvar->varParam.ptr()) { - MultiStaticPtr varParams = new MultiStatic(); - for (size_t i = gvar->params.size(); i < x->params.size(); ++i) - varParams->add(x->params[i]); - addLocal(x->env, gvar->varParam, varParams.ptr()); - } - } - x->analyzing = true; - evaluatePredicate(x->gvar->patternVars, x->gvar->predicate, x->env); - PVData pv = analyzeOne(x->expr, x->env); - x->analyzing = false; - if (!pv.ok()) - return nullptr; - x->analysis = new MultiPValue(PVData(pv.type, false)); - x->type = pv.type; - return x->analysis; + case PVALUE: { + PValue *y = (PValue *)x.ptr(); + return new MultiPValue(y->data); + } + + case MULTI_PVALUE: { + MultiPValue *y = (MultiPValue *)x.ptr(); + return y; } - // - // analyzeExternalVariable - // + case PATTERN: + case MULTI_PATTERN: + error("pattern variable cannot be used as value"); + return nullptr; - PVData analyzeExternalVariable(ExternalVariablePtr x) { - if (!x->type2) - x->type2 = evaluateType(x->type, x->env); - return PVData(x->type2, false); + default: + invalidStaticObjectError(x); + return nullptr; } +} - // - // analyzeExternalProcedure - // +// +// lookupGVarInstance, defaultGVarInstance +// analyzeGVarIndexing, analyzeGVarInstance +// - void analyzeExternalProcedure(ExternalProcedurePtr x) { - if (x->analyzed) - return; - if (!x->attributesVerified) - verifyAttributes(x); - vector argTypes; - for (size_t i = 0; i < x->args.size(); ++i) { - ExternalArgPtr y = x->args[i]; - y->type2 = evaluateType(y->type, x->env); - argTypes.push_back(y->type2); - } - if (!x->returnType) - x->returnType2 = nullptr; - else - x->returnType2 = evaluateType(x->returnType, x->env); - x->ptrType = cCodePointerType(x->callingConv, argTypes, - x->hasVarArgs, x->returnType2); - x->analyzed = true; +GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, + llvm::ArrayRef params) { + if (!x->instances) + x->instances = new ObjectTable(); + Pointer &y = x->instances->lookup(params); + if (!y) { + y = new GVarInstance(x, params); } + return (GVarInstance *)y.ptr(); +} - // - // verifyAttributes - // +GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x) { + return lookupGVarInstance(x, vector()); +} - void verifyAttributes(ExternalProcedurePtr x) { - assert(!x->attributesVerified); - x->attributesVerified = true; - x->attrDLLImport = false; - x->attrDLLExport = false; - int callingConv = -1; - x->attrAsmLabel = ""; +GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, ExprListPtr args, + EnvPtr env) { + assert(x->hasParams()); + MultiStaticPtr params = evaluateMultiStatic(args, env); + if (x->varParam.ptr()) { + if (params->size() < x->params.size()) + arityError2(x->params.size(), params->size()); + } else { + ensureArity(params, x->params.size()); + } + return lookupGVarInstance(x, params->values); +} - MultiStaticPtr attrs = evaluateMultiStatic(x->attributes, x->env); +MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x) { + if (x->analysis.ptr()) + return x->analysis; + CompileContextPusher pusher(x->gvar.ptr(), x->params); + if (x->analyzing) { + updateAnalysisErrorLocation(); + return nullptr; + } + GlobalVariablePtr gvar = x->gvar; + if (!x->expr) + x->expr = clone(gvar->expr); + if (!x->env) { + x->env = new Env(gvar->env); + for (size_t i = 0; i < gvar->params.size(); ++i) { + addLocal(x->env, gvar->params[i], x->params[i]); + } + if (gvar->varParam.ptr()) { + MultiStaticPtr varParams = new MultiStatic(); + for (size_t i = gvar->params.size(); i < x->params.size(); ++i) + varParams->add(x->params[i]); + addLocal(x->env, gvar->varParam, varParams.ptr()); + } + } + x->analyzing = true; + evaluatePredicate(x->gvar->patternVars, x->gvar->predicate, x->env); + PVData pv = analyzeOne(x->expr, x->env); + x->analyzing = false; + if (!pv.ok()) + return nullptr; + x->analysis = new MultiPValue(PVData(pv.type, false)); + x->type = pv.type; + return x->analysis; +} - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; +// +// analyzeExternalVariable +// - switch (obj->objKind) { - case PRIM_OP: { - PrimOp *y = (PrimOp *) obj.ptr(); - switch (y->primOpCode) { - case PRIM_AttributeStdCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_STDCALL; - break; - } - case PRIM_AttributeFastCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_FASTCALL; - break; - } - case PRIM_AttributeThisCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_THISCALL; - break; - } - case PRIM_AttributeCCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_DEFAULT; - break; - } - case PRIM_AttributeLLVMCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_LLVM; - break; - } - case PRIM_AttributeDLLImport: { - if (x->attrDLLExport) - error(x, "dllimport specified after dllexport in external attributes"); - x->attrDLLImport = true; - break; - } - case PRIM_AttributeDLLExport: { - if (x->attrDLLImport) - error(x, "dllexport specified after dllimport in external attributes"); - x->attrDLLExport = true; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external function attribute: "; - printStaticName(os, obj); - error(x, os.str()); - } - } - break; - } - case IDENTIFIER: { - Identifier *y = (Identifier *) obj.ptr(); - x->attrAsmLabel = y->str; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external function attribute: "; - printStaticName(os, obj); - error(x, os.str()); - } - } - } - if (callingConv == -1) - callingConv = CC_DEFAULT; - x->callingConv = (CallingConv) callingConv; - } +PVData analyzeExternalVariable(ExternalVariablePtr x) { + if (!x->type2) + x->type2 = evaluateType(x->type, x->env); + return PVData(x->type2, false); +} - void verifyAttributes(ExternalVariablePtr var) { - assert(!var->attributesVerified); - var->attributesVerified = true; - var->attrDLLImport = false; - var->attrDLLExport = false; +// +// analyzeExternalProcedure +// - MultiStaticPtr attrs = evaluateMultiStatic(var->attributes, var->env); +void analyzeExternalProcedure(ExternalProcedurePtr x) { + if (x->analyzed) + return; + if (!x->attributesVerified) + verifyAttributes(x); + vector argTypes; + for (size_t i = 0; i < x->args.size(); ++i) { + ExternalArgPtr y = x->args[i]; + y->type2 = evaluateType(y->type, x->env); + argTypes.push_back(y->type2); + } + if (!x->returnType) + x->returnType2 = nullptr; + else + x->returnType2 = evaluateType(x->returnType, x->env); + x->ptrType = cCodePointerType(x->callingConv, argTypes, x->hasVarArgs, + x->returnType2); + x->analyzed = true; +} - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; +// +// verifyAttributes +// + +void verifyAttributes(ExternalProcedurePtr x) { + assert(!x->attributesVerified); + x->attributesVerified = true; + x->attrDLLImport = false; + x->attrDLLExport = false; + int callingConv = -1; + x->attrAsmLabel = ""; + + MultiStaticPtr attrs = evaluateMultiStatic(x->attributes, x->env); - if (obj->objKind != PRIM_OP) { + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; + + switch (obj->objKind) { + case PRIM_OP: { + PrimOp *y = (PrimOp *)obj.ptr(); + switch (y->primOpCode) { + case PRIM_AttributeStdCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_STDCALL; + break; + } + case PRIM_AttributeFastCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_FASTCALL; + break; + } + case PRIM_AttributeThisCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_THISCALL; + break; + } + case PRIM_AttributeCCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_DEFAULT; + break; + } + case PRIM_AttributeLLVMCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_LLVM; + break; + } + case PRIM_AttributeDLLImport: { + if (x->attrDLLExport) + error(x, "dllimport specified after dllexport in external " + "attributes"); + x->attrDLLImport = true; + break; + } + case PRIM_AttributeDLLExport: { + if (x->attrDLLImport) + error(x, "dllexport specified after dllimport in external " + "attributes"); + x->attrDLLExport = true; + break; + } + default: { string buf; llvm::raw_string_ostream os(buf); - os << "invalid external variable attribute: "; + os << "invalid external function attribute: "; printStaticName(os, obj); - error(var, os.str()); + error(x, os.str()); } - - PrimOp *y = (PrimOp *) obj.ptr(); - switch (y->primOpCode) { - case PRIM_AttributeDLLImport: { - if (var->attrDLLExport) - error(var, "dllimport specified after dllexport in external attributes"); - var->attrDLLImport = true; - break; - } - case PRIM_AttributeDLLExport: { - if (var->attrDLLImport) - error(var, "dllexport specified after dllimport in external attributes"); - var->attrDLLExport = true; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external variable attribute: "; - printStaticName(os, obj); - error(var, os.str()); - } } + break; + } + case IDENTIFIER: { + Identifier *y = (Identifier *)obj.ptr(); + x->attrAsmLabel = y->str; + break; + } + default: { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external function attribute: "; + printStaticName(os, obj); + error(x, os.str()); + } } } + if (callingConv == -1) + callingConv = CC_DEFAULT; + x->callingConv = (CallingConv)callingConv; +} - void verifyAttributes(ModulePtr mod) { - assert(!mod->attributesVerified); - mod->attributesVerified = true; +void verifyAttributes(ExternalVariablePtr var) { + assert(!var->attributesVerified); + var->attributesVerified = true; + var->attrDLLImport = false; + var->attrDLLExport = false; - if (mod->declaration != nullptr && mod->declaration->attributes != nullptr) { - MultiStaticPtr attrs = evaluateMultiStatic(mod->declaration->attributes, mod->env); + MultiStaticPtr attrs = evaluateMultiStatic(var->attributes, var->env); - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; - switch (obj->objKind) { - case TYPE: { - if (obj->objKind == TYPE) { - Type *ty = (Type *) obj.ptr(); - if (ty->typeKind == FLOAT_TYPE) { - mod->attrDefaultFloatType = (FloatType *) ty; - } else if (ty->typeKind == INTEGER_TYPE) { - mod->attrDefaultIntegerType = (IntegerType *) ty; - } - } - break; - } - case IDENTIFIER: { - Identifier *y = (Identifier *) obj.ptr(); - mod->attrBuildFlags.push_back(y->str); - break; + if (obj->objKind != PRIM_OP) { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external variable attribute: "; + printStaticName(os, obj); + error(var, os.str()); + } + + PrimOp *y = (PrimOp *)obj.ptr(); + switch (y->primOpCode) { + case PRIM_AttributeDLLImport: { + if (var->attrDLLExport) + error(var, "dllimport specified after dllexport in external " + "attributes"); + var->attrDLLImport = true; + break; + } + case PRIM_AttributeDLLExport: { + if (var->attrDLLImport) + error(var, "dllexport specified after dllimport in external " + "attributes"); + var->attrDLLExport = true; + break; + } + default: { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external variable attribute: "; + printStaticName(os, obj); + error(var, os.str()); + } + } + } +} + +void verifyAttributes(ModulePtr mod) { + assert(!mod->attributesVerified); + mod->attributesVerified = true; + + if (mod->declaration != nullptr && + mod->declaration->attributes != nullptr) { + MultiStaticPtr attrs = + evaluateMultiStatic(mod->declaration->attributes, mod->env); + + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; + + switch (obj->objKind) { + case TYPE: { + if (obj->objKind == TYPE) { + Type *ty = (Type *)obj.ptr(); + if (ty->typeKind == FLOAT_TYPE) { + mod->attrDefaultFloatType = (FloatType *)ty; + } else if (ty->typeKind == INTEGER_TYPE) { + mod->attrDefaultIntegerType = (IntegerType *)ty; } - default: - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid module attribute: "; - printStaticName(os, obj); - error(mod->declaration, os.str()); } + break; + } + case IDENTIFIER: { + Identifier *y = (Identifier *)obj.ptr(); + mod->attrBuildFlags.push_back(y->str); + break; + } + default: + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid module attribute: "; + printStaticName(os, obj); + error(mod->declaration, os.str()); } } } +} - // - // analyzeIndexingExpr - // - - static bool isTypeConstructor(ObjectPtr x) { - if (x->objKind == PRIM_OP) { - PrimOpPtr y = (PrimOp *) x.ptr(); - switch (y->primOpCode) { - case PRIM_Pointer: - case PRIM_CodePointer: - case PRIM_ExternalCodePointer: - case PRIM_Array: - case PRIM_Vec: - case PRIM_Tuple: - case PRIM_Union: - case PRIM_Static: - return true; - default: - return false; - } - } else if (x->objKind == RECORD_DECL) { +// +// analyzeIndexingExpr +// + +static bool isTypeConstructor(ObjectPtr x) { + if (x->objKind == PRIM_OP) { + PrimOpPtr y = (PrimOp *)x.ptr(); + switch (y->primOpCode) { + case PRIM_Pointer: + case PRIM_CodePointer: + case PRIM_ExternalCodePointer: + case PRIM_Array: + case PRIM_Vec: + case PRIM_Tuple: + case PRIM_Union: + case PRIM_Static: return true; - } else if (x->objKind == VARIANT_DECL) { - return true; - } else { + default: return false; } + } else if (x->objKind == RECORD_DECL) { + return true; + } else if (x->objKind == VARIANT_DECL) { + return true; + } else { + return false; } +} - MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env) { - PVData pv = analyzeOne(indexable, env); - if (!pv.ok()) - return nullptr; - ObjectPtr obj = unwrapStaticType(pv.type); - if (obj.ptr()) { - if (isTypeConstructor(obj)) { - MultiStaticPtr params = evaluateMultiStatic(args, env); - PVData out = analyzeTypeConstructor(obj, params); - return new MultiPValue(out); - } - if (obj->objKind == GLOBAL_ALIAS) { - GlobalAlias *x = (GlobalAlias *) obj.ptr(); - return analyzeAliasIndexing(x, args, env); - } - if (obj->objKind == GLOBAL_VARIABLE) { - GlobalVariable *x = (GlobalVariable *) obj.ptr(); - GVarInstancePtr y = analyzeGVarIndexing(x, args, env); - return analyzeGVarInstance(y); - } - if (obj->objKind != VALUE_HOLDER && obj->objKind != IDENTIFIER) - error("invalid indexing operation"); - } - ExprListPtr args2 = new ExprList(indexable); - args2->add(args); - return analyzeCallExpr(operator_expr_index(), args2, env); - } - - // - // unwrapByRef - // - - bool unwrapByRef(TypePtr &t) { - if (t->typeKind == RECORD_TYPE) { - RecordType *rt = (RecordType *) t.ptr(); - if (rt->record.ptr() == primitive_ByRef().ptr()) { - assert(rt->params.size() == 1); - ObjectPtr obj = rt->params[0]; - if (obj->objKind != TYPE) { - string buf; - llvm::raw_string_ostream ostr(buf); - ostr << "invalid return type: " << t; - error(ostr.str()); - } - t = (Type *) obj.ptr(); - return true; +MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, + EnvPtr env) { + PVData pv = analyzeOne(indexable, env); + if (!pv.ok()) + return nullptr; + ObjectPtr obj = unwrapStaticType(pv.type); + if (obj.ptr()) { + if (isTypeConstructor(obj)) { + MultiStaticPtr params = evaluateMultiStatic(args, env); + PVData out = analyzeTypeConstructor(obj, params); + return new MultiPValue(out); + } + if (obj->objKind == GLOBAL_ALIAS) { + GlobalAlias *x = (GlobalAlias *)obj.ptr(); + return analyzeAliasIndexing(x, args, env); + } + if (obj->objKind == GLOBAL_VARIABLE) { + GlobalVariable *x = (GlobalVariable *)obj.ptr(); + GVarInstancePtr y = analyzeGVarIndexing(x, args, env); + return analyzeGVarInstance(y); + } + if (obj->objKind != VALUE_HOLDER && obj->objKind != IDENTIFIER) + error("invalid indexing operation"); + } + ExprListPtr args2 = new ExprList(indexable); + args2->add(args); + return analyzeCallExpr(operator_expr_index(), args2, env); +} + +// +// unwrapByRef +// + +bool unwrapByRef(TypePtr &t) { + if (t->typeKind == RECORD_TYPE) { + RecordType *rt = (RecordType *)t.ptr(); + if (rt->record.ptr() == primitive_ByRef().ptr()) { + assert(rt->params.size() == 1); + ObjectPtr obj = rt->params[0]; + if (obj->objKind != TYPE) { + string buf; + llvm::raw_string_ostream ostr(buf); + ostr << "invalid return type: " << t; + error(ostr.str()); } + t = (Type *)obj.ptr(); + return true; } - return false; } + return false; +} - // - // constructType - // +// +// constructType +// - TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args) { - if (constructor->objKind == PRIM_OP) { - PrimOpPtr x = (PrimOp *) constructor.ptr(); +TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args) { + if (constructor->objKind == PRIM_OP) { + PrimOpPtr x = (PrimOp *)constructor.ptr(); - switch (x->primOpCode) { - case PRIM_Pointer: { - ensureArity(args, 1); - TypePtr pointeeType = staticToType(args, 0); - return pointerType(pointeeType); - } + switch (x->primOpCode) { + case PRIM_Pointer: { + ensureArity(args, 1); + TypePtr pointeeType = staticToType(args, 0); + return pointerType(pointeeType); + } - case PRIM_CodePointer: { - ensureArity(args, 2); - vector argTypes; - staticToTypeTuple(args, 0, argTypes); - vector returnTypes; - staticToTypeTuple(args, 1, returnTypes); - vector returnIsRef(returnTypes.size(), false); - for (size_t i = 0; i < returnTypes.size(); ++i) - returnIsRef[i] = unwrapByRef(returnTypes[i]); - return codePointerType(argTypes, returnIsRef, returnTypes); - } + case PRIM_CodePointer: { + ensureArity(args, 2); + vector argTypes; + staticToTypeTuple(args, 0, argTypes); + vector returnTypes; + staticToTypeTuple(args, 1, returnTypes); + vector returnIsRef(returnTypes.size(), false); + for (size_t i = 0; i < returnTypes.size(); ++i) + returnIsRef[i] = unwrapByRef(returnTypes[i]); + return codePointerType(argTypes, returnIsRef, returnTypes); + } - case PRIM_ExternalCodePointer: { - ensureArity(args, 4); - - CallingConv cc = staticToCallingConv(args, 0); - bool hasVarArgs = staticToBool(args, 1); - vector argTypes; - staticToTypeTuple(args, 2, argTypes); - vector returnTypes; - staticToTypeTuple(args, 3, returnTypes); - if (returnTypes.size() > 1) - argumentError(1, "C code cannot return more than one value"); - TypePtr returnType; - if (returnTypes.size() == 1) - returnType = returnTypes[0]; - return cCodePointerType(cc, argTypes, hasVarArgs, returnType); - } + case PRIM_ExternalCodePointer: { + ensureArity(args, 4); - case PRIM_Array: { - ensureArity(args, 2); - TypePtr t = staticToType(args, 0); - return arrayType(t, unsigned(staticToInt(args, 1))); - } + CallingConv cc = staticToCallingConv(args, 0); + bool hasVarArgs = staticToBool(args, 1); + vector argTypes; + staticToTypeTuple(args, 2, argTypes); + vector returnTypes; + staticToTypeTuple(args, 3, returnTypes); + if (returnTypes.size() > 1) + argumentError(1, "C code cannot return more than one value"); + TypePtr returnType; + if (returnTypes.size() == 1) + returnType = returnTypes[0]; + return cCodePointerType(cc, argTypes, hasVarArgs, returnType); + } - case PRIM_Vec: { - ensureArity(args, 2); - TypePtr t = staticToType(args, 0); - return vecType(t, unsigned(staticToInt(args, 1))); - } + case PRIM_Array: { + ensureArity(args, 2); + TypePtr t = staticToType(args, 0); + return arrayType(t, unsigned(staticToInt(args, 1))); + } - case PRIM_Tuple: { - vector types; - for (size_t i = 0; i < args->size(); ++i) - types.push_back(staticToType(args, i)); - return tupleType(types); - } + case PRIM_Vec: { + ensureArity(args, 2); + TypePtr t = staticToType(args, 0); + return vecType(t, unsigned(staticToInt(args, 1))); + } - case PRIM_Union: { - vector types; - for (size_t i = 0; i < args->size(); ++i) - types.push_back(staticToType(args, i)); - return unionType(types); - } + case PRIM_Tuple: { + vector types; + for (size_t i = 0; i < args->size(); ++i) + types.push_back(staticToType(args, i)); + return tupleType(types); + } - case PRIM_Static: { - ensureArity(args, 1); - return staticType(args->values[0]); - } + case PRIM_Union: { + vector types; + for (size_t i = 0; i < args->size(); ++i) + types.push_back(staticToType(args, i)); + return unionType(types); + } - default: - assert(false); - return nullptr; - } - } else if (constructor->objKind == RECORD_DECL) { - RecordDeclPtr x = (RecordDecl *) constructor.ptr(); - if (x->varParam.ptr()) { - if (args->size() < x->params.size()) - arityError2(x->params.size(), args->size()); - } else { - ensureArity(args, x->params.size()); - } - return recordType(x, args->values); - } else if (constructor->objKind == VARIANT_DECL) { - VariantDeclPtr x = (VariantDecl *) constructor.ptr(); - if (x->varParam.ptr()) { - if (args->size() < x->params.size()) - arityError2(x->params.size(), args->size()); - } else { - ensureArity(args, x->params.size()); - } - return variantType(x, args->values); - } else { + case PRIM_Static: { + ensureArity(args, 1); + return staticType(args->values[0]); + } + + default: assert(false); return nullptr; } + } else if (constructor->objKind == RECORD_DECL) { + RecordDeclPtr x = (RecordDecl *)constructor.ptr(); + if (x->varParam.ptr()) { + if (args->size() < x->params.size()) + arityError2(x->params.size(), args->size()); + } else { + ensureArity(args, x->params.size()); + } + return recordType(x, args->values); + } else if (constructor->objKind == VARIANT_DECL) { + VariantDeclPtr x = (VariantDecl *)constructor.ptr(); + if (x->varParam.ptr()) { + if (args->size() < x->params.size()) + arityError2(x->params.size(), args->size()); + } else { + ensureArity(args, x->params.size()); + } + return variantType(x, args->values); + } else { + assert(false); + return nullptr; } +} - // - // analyzeTypeConstructor - // +// +// analyzeTypeConstructor +// - PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args) { - TypePtr t = constructType(obj, args); - return staticPValue(t.ptr()); - } +PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args) { + TypePtr t = constructType(obj, args); + return staticPValue(t.ptr()); +} - // - // analyzeAliasIndexing - // +// +// analyzeAliasIndexing +// + +MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, ExprListPtr args, + EnvPtr env) { + assert(x->hasParams()); + MultiStaticPtr params = evaluateMultiStatic(args, env); + if (x->varParam.ptr()) { + if (params->size() < x->params.size()) + arityError2(x->params.size(), params->size()); + } else { + ensureArity(params, x->params.size()); + } + EnvPtr bodyEnv = new Env(x->env); + for (size_t i = 0; i < x->params.size(); ++i) { + addLocal(bodyEnv, x->params[i], params->values[i]); + } + if (x->varParam.ptr()) { + MultiStaticPtr varParams = new MultiStatic(); + for (size_t i = x->params.size(); i < params->size(); ++i) + varParams->add(params->values[i]); + addLocal(bodyEnv, x->varParam, varParams.ptr()); + } + evaluatePredicate(x->patternVars, x->predicate, bodyEnv); + AnalysisCachingDisabler disabler; + return analyzeExpr(x->expr, bodyEnv); +} - MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, - ExprListPtr args, - EnvPtr env) { - assert(x->hasParams()); - MultiStaticPtr params = evaluateMultiStatic(args, env); - if (x->varParam.ptr()) { - if (params->size() < x->params.size()) - arityError2(x->params.size(), params->size()); - } else { - ensureArity(params, x->params.size()); +// +// analyzeReturn +// + +MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, + llvm::ArrayRef returnTypes) { + MultiPValuePtr x = new MultiPValue(); + for (size_t i = 0; i < returnTypes.size(); ++i) { + PVData pv = PVData(returnTypes[i], !returnIsRef[i]); + x->values.push_back(pv); + } + return x.ptr(); +} + +// +// analyzeIntrinsic +// + +// this class is designed to pervert the intrinsic verification code +// in llvm/Intrinsics.gen, selected by #define GET_INTRINSIC_VERIFIER, +// into doing type checking and output type propagation for an intrinsic. +// GET_INTRINSIC_VERIFIER contains a function body that expects to have +// the following in scope: +// - namespace llvm +// - int-sized bit mask constants `ExtendedElementVectorType` and +// `TruncatedElementVectorType` +// - an `llvm::Intrinsic::ID ID` +// - an `llvm::FunctionType *IF`. This is unused by our code, so we provide +// a dummy IF variable instead +// - a function that can be called as +// `VerifyIntrinsicPrototype(ID, IF, numReturns, numArgs, ...)` +// where the varargs are either values from the llvm::MVT::SimpleValueType +// enum signifying the expected return or argument type, or negative values +// equal to `~index`, indicating that that argument must be the same type as +// the `index`th vararg. +struct IntrinsicAnalyzer { + llvm::Intrinsic::ID ID; + llvm::ArrayRef inputTypes; + + string outError; + llvm::SmallVector ArgTys; + + IntrinsicAnalyzer(llvm::Intrinsic::ID ID, + llvm::ArrayRef inputTypes) + : ID(ID), inputTypes(inputTypes) {} + + static void + skipReturnType(llvm::ArrayRef &Infos) { + using namespace llvm; + using namespace Intrinsic; + IITDescriptor D = Infos.front(); + Infos = Infos.slice(1); + + switch (D.Kind) { + case IITDescriptor::Void: + return; + case IITDescriptor::MMX: + return; + case IITDescriptor::Metadata: + return; + case IITDescriptor::Float: + return; + case IITDescriptor::Double: + return; + case IITDescriptor::Integer: + return; + case IITDescriptor::Vector: + skipReturnType(Infos); + return; + case IITDescriptor::Pointer: + skipReturnType(Infos); + return; + case IITDescriptor::Struct: { + for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) + skipReturnType(Infos); + return; } - EnvPtr bodyEnv = new Env(x->env); - for (size_t i = 0; i < x->params.size(); ++i) { - addLocal(bodyEnv, x->params[i], params->values[i]); + case IITDescriptor::Argument: + return; + case IITDescriptor::ExtendArgument: + return; + case IITDescriptor::TruncArgument: + return; + default: + return; } - if (x->varParam.ptr()) { - MultiStaticPtr varParams = new MultiStatic(); - for (size_t i = x->params.size(); i < params->size(); ++i) - varParams->add(params->values[i]); - addLocal(bodyEnv, x->varParam, varParams.ptr()); - } - evaluatePredicate(x->patternVars, x->predicate, bodyEnv); - AnalysisCachingDisabler disabler; - return analyzeExpr(x->expr, bodyEnv); - } - - // - // analyzeReturn - // - - MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, - llvm::ArrayRef returnTypes) { - MultiPValuePtr x = new MultiPValue(); - for (size_t i = 0; i < returnTypes.size(); ++i) { - PVData pv = PVData(returnTypes[i], !returnIsRef[i]); - x->values.push_back(pv); - } - return x.ptr(); - } - - // - // analyzeIntrinsic - // - - // this class is designed to pervert the intrinsic verification code - // in llvm/Intrinsics.gen, selected by #define GET_INTRINSIC_VERIFIER, - // into doing type checking and output type propagation for an intrinsic. - // GET_INTRINSIC_VERIFIER contains a function body that expects to have - // the following in scope: - // - namespace llvm - // - int-sized bit mask constants `ExtendedElementVectorType` and `TruncatedElementVectorType` - // - an `llvm::Intrinsic::ID ID` - // - an `llvm::FunctionType *IF`. This is unused by our code, so we provide - // a dummy IF variable instead - // - a function that can be called as - // `VerifyIntrinsicPrototype(ID, IF, numReturns, numArgs, ...)` - // where the varargs are either values from the llvm::MVT::SimpleValueType enum - // signifying the expected return or argument type, or negative values - // equal to `~index`, indicating that that argument must be the same type as - // the `index`th vararg. - struct IntrinsicAnalyzer { - llvm::Intrinsic::ID ID; - llvm::ArrayRef inputTypes; - - string outError; - llvm::SmallVector ArgTys; - - IntrinsicAnalyzer(llvm::Intrinsic::ID ID, - llvm::ArrayRef inputTypes) - : ID(ID), inputTypes(inputTypes) { - } - - static void skipReturnType( - llvm::ArrayRef &Infos) { - using namespace llvm; - using namespace Intrinsic; - IITDescriptor D = Infos.front(); - Infos = Infos.slice(1); - - switch (D.Kind) { - case IITDescriptor::Void: return; - case IITDescriptor::MMX: return; - case IITDescriptor::Metadata: return; - case IITDescriptor::Float: return; - case IITDescriptor::Double: return; - case IITDescriptor::Integer: return; - case IITDescriptor::Vector: - skipReturnType(Infos); - return; - case IITDescriptor::Pointer: - skipReturnType(Infos); - return; - case IITDescriptor::Struct: { - for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - skipReturnType(Infos); - return; - } - case IITDescriptor::Argument: return; - case IITDescriptor::ExtendArgument: return; - case IITDescriptor::TruncArgument: return; - default: return; + llvm_unreachable("unhandled"); + } + + void + VerifyIntrinsicType(llvm::Type *Ty, + llvm::ArrayRef &Infos, + llvm::raw_string_ostream &errors, size_t ai) { + using namespace llvm; + using namespace Intrinsic; + + // If we ran out of descriptors, there are too many arguments. + if (Infos.empty()) { + errors << "intrinsic has too many arguments"; + return; + } + IITDescriptor D = Infos.front(); + Infos = Infos.slice(1); + + switch (D.Kind) { + case IITDescriptor::Void: + if (!Ty->isVoidTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM void type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::MMX: + if (!Ty->isX86_AMXTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM MMX type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Metadata: + if (!Ty->isMetadataTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM metadata type, but got "; + Ty->print(errors); } - llvm_unreachable("unhandled"); + return; + case IITDescriptor::Float: + if (!Ty->isFloatTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM float type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Double: + if (!Ty->isDoubleTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM double type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Integer: + if (!Ty->isIntegerTy(D.Integer_Width)) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM i" << D.Integer_Width + << " type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Vector: { + llvm::VectorType *VT = dyn_cast(Ty); + if (VT == nullptr) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); + } else if (VT->getElementCount() != D.Vector_Width) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type with " + << D.Vector_Width << " elements, but got "; + Ty->print(errors); + } + VerifyIntrinsicType(VT->getElementType(), Infos, errors, ai); + return; + } + case IITDescriptor::Pointer: { + llvm::PointerType *PT = dyn_cast(Ty); + if (PT == 0) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type, but got "; + Ty->print(errors); + } else if (PT->getAddressSpace() != D.Pointer_AddressSpace) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type with" + << D.Pointer_AddressSpace << " address space, but got "; + Ty->print(errors); + } + VerifyIntrinsicType(PT->getElementType(), Infos, errors, ai); + return; } - void VerifyIntrinsicType( - llvm::Type *Ty, - llvm::ArrayRef &Infos, - llvm::raw_string_ostream &errors, size_t ai) { - using namespace llvm; - using namespace Intrinsic; + case IITDescriptor::Struct: { + llvm::StructType *ST = dyn_cast(Ty); + if (ST == 0) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM struct type, but got "; + Ty->print(errors); + } else if (ST->getNumElements() != D.Struct_NumElements) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM struct type with " + << D.Struct_NumElements << " elements, but got "; + Ty->print(errors); + } + for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) + VerifyIntrinsicType(ST->getElementType(i), Infos, errors, ai); + return; + } - // If we ran out of descriptors, there are too many arguments. - if (Infos.empty()) { - errors << "intrinsic has too many arguments"; + case IITDescriptor::Argument: + // Two cases here - If this is the second occurrence of an argument, + // verify that the later instance matches the previous instance. + if (D.getArgumentNumber() < ArgTys.size()) { + if (Ty != ArgTys[D.getArgumentNumber()]) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM type of argument " + << D.getArgumentNumber() << ", which is "; + ArgTys[D.getArgumentNumber()]->print(errors); + errors << ", but got "; + Ty->print(errors); + } return; } - IITDescriptor D = Infos.front(); - Infos = Infos.slice(1); - - switch (D.Kind) { - case IITDescriptor::Void: - if (!Ty->isVoidTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM void type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::MMX: - if (!Ty->isX86_MMXTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM MMX type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Metadata: - if (!Ty->isMetadataTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM metadata type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Float: - if (!Ty->isFloatTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM float type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Double: - if (!Ty->isDoubleTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM double type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Integer: - if (!Ty->isIntegerTy(D.Integer_Width)) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM i" << D.Integer_Width - << " type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Vector: { - llvm::VectorType *VT = dyn_cast(Ty); - if (VT == 0) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } else if (VT->getNumElements() != D.Vector_Width) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type with " - << D.Vector_Width - << " elements, but got "; - Ty->print(errors); - } - VerifyIntrinsicType(VT->getElementType(), Infos, errors, ai); - return; + + // Otherwise, if this is the first instance of an argument, record + // it and verify the "Any" kind. + assert(D.getArgumentNumber() == ArgTys.size() && + "Table consistency error"); + ArgTys.push_back(Ty); + + switch (D.getArgumentKind()) { + case IITDescriptor::AK_AnyInteger: + if (!Ty->isIntOrIntVectorTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM integer type, but got "; + Ty->print(errors); } - case IITDescriptor::Pointer: { - llvm::PointerType *PT = dyn_cast(Ty); - if (PT == 0) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type, but got "; - Ty->print(errors); - } else if (PT->getAddressSpace() != D.Pointer_AddressSpace) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type with" - << D.Pointer_AddressSpace - << " address space, but got "; - Ty->print(errors); - } - VerifyIntrinsicType(PT->getElementType(), Infos, errors, ai); - return; + return; + case IITDescriptor::AK_AnyFloat: + if (!Ty->isFPOrFPVectorTy()) { + errors + << "intrinsic argument " << (ai + 1) + << " must be of an LLVM floating point type, but got "; + Ty->print(errors); } - - case IITDescriptor::Struct: { - llvm::StructType *ST = dyn_cast(Ty); - if (ST == 0) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM struct type, but got "; - Ty->print(errors); - } else if (ST->getNumElements() != D.Struct_NumElements) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM struct type with " - << D.Struct_NumElements - << " elements, but got "; - Ty->print(errors); - } - for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - VerifyIntrinsicType(ST->getElementType(i), Infos, errors, ai); - return; + return; + case IITDescriptor::AK_AnyVector: + if (!isa(Ty)) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::AK_AnyPointer: + if (!isa(Ty)) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type, but got "; + Ty->print(errors); } + return; + default: + return; + } + llvm_unreachable("all argument kinds not covered"); - case IITDescriptor::Argument: - // Two cases here - If this is the second occurrence of an argument, verify - // that the later instance matches the previous instance. - if (D.getArgumentNumber() < ArgTys.size()) { - if (Ty != ArgTys[D.getArgumentNumber()]) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM type of argument " - << D.getArgumentNumber() - << ", which is "; - ArgTys[D.getArgumentNumber()]->print(errors); - errors << ", but got "; - Ty->print(errors); - } - return; - } + case IITDescriptor::ExtendArgument: + // This may only be used when referring to a previous vector + // argument. + if (D.getArgumentNumber() >= ArgTys.size() || + !isa(ArgTys[D.getArgumentNumber()]) || + llvm::VectorType::getExtendedElementVectorType( + cast(ArgTys[D.getArgumentNumber()])) != + Ty) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); + } + return; - // Otherwise, if this is the first instance of an argument, record it and - // verify the "Any" kind. - assert(D.getArgumentNumber() == ArgTys.size() && "Table consistency error"); - ArgTys.push_back(Ty); - - switch (D.getArgumentKind()) { - case IITDescriptor::AK_AnyInteger: - if (!Ty->isIntOrIntVectorTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM integer type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyFloat: - if (!Ty->isFPOrFPVectorTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM floating point type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyVector: - if (!isa(Ty)) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyPointer: - if (!isa(Ty)) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type, but got "; - Ty->print(errors); - } - return; - default: return; - } - llvm_unreachable("all argument kinds not covered"); - - case IITDescriptor::ExtendArgument: - // This may only be used when referring to a previous vector argument. - if (D.getArgumentNumber() >= ArgTys.size() || - !isa(ArgTys[D.getArgumentNumber()]) || - llvm::VectorType::getExtendedElementVectorType( - cast( - ArgTys[D.getArgumentNumber()])) != Ty) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - - case IITDescriptor::TruncArgument: - // This may only be used when referring to a previous vector argument. - if (D.getArgumentNumber() >= ArgTys.size() || - !isa(ArgTys[D.getArgumentNumber()]) || - llvm::VectorType::getTruncatedElementVectorType( - cast( - ArgTys[D.getArgumentNumber()])) != Ty) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - default: return; + case IITDescriptor::TruncArgument: + // This may only be used when referring to a previous vector + // argument. + if (D.getArgumentNumber() >= ArgTys.size() || + !isa(ArgTys[D.getArgumentNumber()]) || + llvm::VectorType::getTruncatedElementVectorType( + cast(ArgTys[D.getArgumentNumber()])) != + Ty) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); } - llvm_unreachable("unhandled"); + return; + default: + return; } + llvm_unreachable("unhandled"); + } - void run() { - using namespace llvm; + void run() { + using namespace llvm; - llvm::raw_string_ostream errors(outError); + llvm::raw_string_ostream errors(outError); - SmallVector Table; - getIntrinsicInfoTableEntries(ID, Table); - ArrayRef TableRef = Table; + SmallVector Table; + getIntrinsicInfoTableEntries(ID, Table); + ArrayRef TableRef = Table; - skipReturnType(TableRef); + skipReturnType(TableRef); - for (unsigned i = 0, e = inputTypes.size(); i != e; ++i) { - VerifyIntrinsicType(inputTypes[i], TableRef, errors, i); - } - if (!TableRef.empty()) { - errors << "intrinsic has too few arguments"; - } + for (unsigned i = 0, e = inputTypes.size(); i != e; ++i) { + VerifyIntrinsicType(inputTypes[i], TableRef, errors, i); + } + if (!TableRef.empty()) { + errors << "intrinsic has too few arguments"; } - - bool ok() const { return outError.empty(); } - }; - - static TypePtr intrinsicOutputType(llvm::Type *ty) { - if (llvm::IntegerType *intTy = llvm::dyn_cast(ty)) { - switch (intTy->getBitWidth()) { - case 8: - return uint8Type; - case 16: - return uint16Type; - case 32: - return uint32Type; - case 64: - return uint64Type; - case 128: - return uint128Type; - default: - return nullptr; - } - } else if (ty == llvm::Type::getFloatTy(ty->getContext())) - return float32Type; - else if (ty == llvm::Type::getDoubleTy(ty->getContext())) - return float64Type; - else if (auto *pointerTy = llvm::dyn_cast(ty)) { - TypePtr baseType = intrinsicOutputType(pointerTy->getPointerElementType()); - if (baseType != nullptr) - return pointerType(baseType); - else - return nullptr; - } else if (auto *vectorTy = llvm::dyn_cast(ty)) { - TypePtr baseType = intrinsicOutputType(vectorTy->getElementType()); - if (baseType != nullptr) - return vecType(baseType, vectorTy->getNumElements()); - else - return nullptr; - } else - return nullptr; } - static MultiPValuePtr intrinsicOutputTypes(llvm::Function *instance) { - MultiPValuePtr ret = new MultiPValue(); - llvm::Type *ty = instance->getFunctionType()->getReturnType(); - - if (ty->isVoidTy()) - return ret; + bool ok() const { return outError.empty(); } +}; - TypePtr outType = intrinsicOutputType(ty); - if (outType == nullptr) { - std::string errorBuf; - llvm::raw_string_ostream errors(errorBuf); - errors << "intrinsic returning LLVM type "; - ty->print(errors); - errors << " not yet supported"; - error(errors.str()); +static TypePtr intrinsicOutputType(llvm::Type *ty) { + if (llvm::IntegerType *intTy = llvm::dyn_cast(ty)) { + switch (intTy->getBitWidth()) { + case 8: + return uint8Type; + case 16: + return uint16Type; + case 32: + return uint32Type; + case 64: + return uint64Type; + case 128: + return uint128Type; + default: + return nullptr; } + } else if (ty == llvm::Type::getFloatTy(ty->getContext())) + return float32Type; + else if (ty == llvm::Type::getDoubleTy(ty->getContext())) + return float64Type; + else if (auto *pointerTy = llvm::dyn_cast(ty)) { + TypePtr baseType = + intrinsicOutputType(pointerTy->getPointerElementType()); + if (baseType != nullptr) + return pointerType(baseType); + else + return nullptr; + } else if (auto *vectorTy = llvm::dyn_cast(ty)) { + TypePtr baseType = intrinsicOutputType(vectorTy->getElementType()); + if (baseType != nullptr) + return vecType(baseType, vectorTy->getNumElements()); + else + return nullptr; + } else + return nullptr; +} + +static MultiPValuePtr intrinsicOutputTypes(llvm::Function *instance) { + MultiPValuePtr ret = new MultiPValue(); + llvm::Type *ty = instance->getFunctionType()->getReturnType(); - ret->add(PVData(outType, true)); + if (ty->isVoidTy()) return ret; + + TypePtr outType = intrinsicOutputType(ty); + if (outType == nullptr) { + std::string errorBuf; + llvm::raw_string_ostream errors(errorBuf); + errors << "intrinsic returning LLVM type "; + ty->print(errors); + errors << " not yet supported"; + error(errors.str()); } - static MultiPValuePtr analyzeIntrinsic(IntrinsicSymbol *intrin, MultiPValue *args) { - vector argsKey; - args->toArgsKey(&argsKey); + ret->add(PVData(outType, true)); + return ret; +} - map, IntrinsicInstance>::const_iterator instancePair - = intrin->instances.find(argsKey); - if (instancePair != intrin->instances.end()) { - IntrinsicInstance const &instance = instancePair->second; - if (!instance.error.empty()) { - error(instance.error); - return nullptr; - } else { - assert(instance.function != nullptr); - return instance.outputTypes; - } +static MultiPValuePtr analyzeIntrinsic(IntrinsicSymbol *intrin, + MultiPValue *args) { + vector argsKey; + args->toArgsKey(&argsKey); + + map, IntrinsicInstance>::const_iterator instancePair = + intrin->instances.find(argsKey); + if (instancePair != intrin->instances.end()) { + IntrinsicInstance const &instance = instancePair->second; + if (!instance.error.empty()) { + error(instance.error); + return nullptr; } else { - vector inputTypes; - for (vector::const_iterator i = argsKey.begin(), end = argsKey.end(); - i != end; - ++i) { - Type *type = i->ptr(); - if (type->typeKind == STATIC_TYPE) { - StaticType *staticType = (StaticType *) type; - if (staticType->obj->objKind != VALUE_HOLDER) - // XXX defer error for analyzeCallDefined - error("intrinsic static arguments must be boolean or integer statics"); - ValueHolder *vh = (ValueHolder *) staticType->obj.ptr(); - type = vh->type.ptr(); - } - inputTypes.push_back(llvmType(type)); - } - IntrinsicAnalyzer ia(intrin->id, inputTypes); - ia.run(); - IntrinsicInstance &instance = intrin->instances[argsKey]; - if (ia.outError.empty()) { - instance.function = llvm::Intrinsic::getOrInsertDeclaration(llvmModule, - intrin->id, - ia.ArgTys); - instance.outputTypes = intrinsicOutputTypes(instance.function); - return instance.outputTypes; - } else { - instance.function = nullptr; - instance.outputTypes = nullptr; - instance.error.swap(ia.outError); - error(instance.error); // XXX factor this out and use in analyzeCallDefined + assert(instance.function != nullptr); + return instance.outputTypes; + } + } else { + vector inputTypes; + for (vector::const_iterator i = argsKey.begin(), + end = argsKey.end(); + i != end; ++i) { + Type *type = i->ptr(); + if (type->typeKind == STATIC_TYPE) { + StaticType *staticType = (StaticType *)type; + if (staticType->obj->objKind != VALUE_HOLDER) + // XXX defer error for analyzeCallDefined + error("intrinsic static arguments must be boolean or " + "integer statics"); + ValueHolder *vh = (ValueHolder *)staticType->obj.ptr(); + type = vh->type.ptr(); + } + inputTypes.push_back(llvmType(type)); + } + IntrinsicAnalyzer ia(intrin->id, inputTypes); + ia.run(); + IntrinsicInstance &instance = intrin->instances[argsKey]; + if (ia.outError.empty()) { + instance.function = llvm::Intrinsic::getOrInsertDeclaration( + llvmModule, intrin->id, ia.ArgTys); + instance.outputTypes = intrinsicOutputTypes(instance.function); + return instance.outputTypes; + } else { + instance.function = nullptr; + instance.outputTypes = nullptr; + instance.error.swap(ia.outError); + error(instance.error); // XXX factor this out and use in + // analyzeCallDefined + return nullptr; + } + } +} + +// +// analyzeCallExpr +// + +MultiPValuePtr analyzeCallExpr(ExprPtr callable, ExprListPtr args, EnvPtr env) { + PVData pv = analyzeOne(callable, env); + if (!pv.ok()) + return nullptr; + switch (pv.type->typeKind) { + case CODE_POINTER_TYPE: { + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) + return nullptr; + return analyzeCallPointer(pv, mpv); + } + default: + break; + } + ObjectPtr obj = unwrapStaticType(pv.type); + if (!obj) { + ExprListPtr args2 = new ExprList(callable); + args2->add(args); + return analyzeCallExpr(operator_expr_call(), args2, env); + } + + switch (obj->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + case PRIM_OP: { + if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { + PrimOpPtr x = (PrimOp *)obj.ptr(); + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) return nullptr; - } + return analyzePrimOp(x, mpv); } + vector dispatchIndices; + MultiPValuePtr mpv = analyzeMultiArgs(args, env, dispatchIndices); + if (!mpv) + return nullptr; + if (dispatchIndices.size() > 0) { + return analyzeDispatch(obj, mpv, dispatchIndices); + } + CompileContextPusher pusher(obj, mpv->values); + InvokeEntry *entry = analyzeCallable(obj, mpv->values); + if (entry->callByName) + return analyzeCallByName(entry, callable, args, env); + if (!entry->analyzed) + return nullptr; + return analyzeReturn(entry->returnIsRef, entry->returnTypes); + } + + case INTRINSIC: { + IntrinsicSymbol *intrin = (IntrinsicSymbol *)obj.ptr(); + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) + return nullptr; + return analyzeIntrinsic(intrin, mpv.ptr()); } - // - // analyzeCallExpr - // + default: + error("invalid call expression"); + return nullptr; + } +} - MultiPValuePtr analyzeCallExpr(ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - PVData pv = analyzeOne(callable, env); - if (!pv.ok()) - return nullptr; - switch (pv.type->typeKind) { - case CODE_POINTER_TYPE: { - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzeCallPointer(pv, mpv); - } - default: - break; - } - ObjectPtr obj = unwrapStaticType(pv.type); - if (!obj) { - ExprListPtr args2 = new ExprList(callable); - args2->add(args); - return analyzeCallExpr(operator_expr_call(), args2, env); - } +// +// analyzeDispatch +// - switch (obj->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - case PRIM_OP: { - if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { - PrimOpPtr x = (PrimOp *) obj.ptr(); - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzePrimOp(x, mpv); - } - vector dispatchIndices; - MultiPValuePtr mpv = analyzeMultiArgs(args, env, dispatchIndices); - if (!mpv) - return nullptr; - if (dispatchIndices.size() > 0) { - return analyzeDispatch(obj, mpv, dispatchIndices); - } - CompileContextPusher pusher(obj, mpv->values); - InvokeEntry *entry = - analyzeCallable(obj, mpv->values); - if (entry->callByName) - return analyzeCallByName(entry, callable, args, env); - if (!entry->analyzed) - return nullptr; - return analyzeReturn(entry->returnIsRef, entry->returnTypes); - } +PVData analyzeDispatchIndex(PVData const &pv, unsigned tag) { + MultiPValuePtr args = new MultiPValue(); + args->add(pv); + ValueHolderPtr vh = intToValueHolder((int)tag); + args->add(staticPValue(vh.ptr())); - case INTRINSIC: { - IntrinsicSymbol *intrin = (IntrinsicSymbol *) obj.ptr(); - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzeIntrinsic(intrin, mpv.ptr()); - } + MultiPValuePtr out = + analyzeCallValue(staticPValue(operator_dispatchIndex()), args); + ensureArity(out, 1); + return out->values[0]; +} - default: - error("invalid call expression"); - return nullptr; - } - } - - // - // analyzeDispatch - // - - PVData analyzeDispatchIndex(PVData const &pv, unsigned tag) { - MultiPValuePtr args = new MultiPValue(); - args->add(pv); - ValueHolderPtr vh = intToValueHolder((int) tag); - args->add(staticPValue(vh.ptr())); - - MultiPValuePtr out = - analyzeCallValue(staticPValue(operator_dispatchIndex()), args); - ensureArity(out, 1); - return out->values[0]; - } - - MultiPValuePtr analyzeDispatch(ObjectPtr obj, - MultiPValuePtr args, - llvm::ArrayRef dispatchIndices) { - if (dispatchIndices.empty()) - return analyzeCallValue(staticPValue(obj), args); - - CompileContextPusher pusher(obj, args->values, dispatchIndices); - - unsigned index = dispatchIndices[0]; - vector dispatchIndices2(dispatchIndices.begin() + 1, - dispatchIndices.end()); - MultiPValuePtr prefix = new MultiPValue(); - for (unsigned i = 0; i < index; ++i) - prefix->add(args->values[i]); - MultiPValuePtr suffix = new MultiPValue(); - for (unsigned i = index + 1; i < args->size(); ++i) - suffix->add(args->values[i]); - PVData const &pvDispatch = args->values[index]; - unsigned memberCount = dispatchTagCount(pvDispatch.type); - - MultiPValuePtr result; - vector dispatchedTypes; - for (unsigned i = 0; i < memberCount; ++i) { - MultiPValuePtr args2 = new MultiPValue(); - args2->add(prefix); - PVData pvDispatch2 = analyzeDispatchIndex(pvDispatch, i); - args2->add(pvDispatch2); - args2->add(suffix); - MultiPValuePtr result2 = analyzeDispatch(obj, args2, dispatchIndices2); - if (!result2) - return nullptr; - if (!result) { - result = result2; +MultiPValuePtr analyzeDispatch(ObjectPtr obj, MultiPValuePtr args, + llvm::ArrayRef dispatchIndices) { + if (dispatchIndices.empty()) + return analyzeCallValue(staticPValue(obj), args); + + CompileContextPusher pusher(obj, args->values, dispatchIndices); + + unsigned index = dispatchIndices[0]; + vector dispatchIndices2(dispatchIndices.begin() + 1, + dispatchIndices.end()); + MultiPValuePtr prefix = new MultiPValue(); + for (unsigned i = 0; i < index; ++i) + prefix->add(args->values[i]); + MultiPValuePtr suffix = new MultiPValue(); + for (unsigned i = index + 1; i < args->size(); ++i) + suffix->add(args->values[i]); + PVData const &pvDispatch = args->values[index]; + unsigned memberCount = dispatchTagCount(pvDispatch.type); + + MultiPValuePtr result; + vector dispatchedTypes; + for (unsigned i = 0; i < memberCount; ++i) { + MultiPValuePtr args2 = new MultiPValue(); + args2->add(prefix); + PVData pvDispatch2 = analyzeDispatchIndex(pvDispatch, i); + args2->add(pvDispatch2); + args2->add(suffix); + MultiPValuePtr result2 = analyzeDispatch(obj, args2, dispatchIndices2); + if (!result2) + return nullptr; + if (!result) { + result = result2; + } else { + bool ok = true; + if (result->size() != result2->size()) { + ok = false; } else { - bool ok = true; - if (result->size() != result2->size()) { - ok = false; - } else { - for (unsigned j = 0; j < result2->size(); ++j) { - PVData const &pv = result->values[j]; - PVData const &pv2 = result2->values[j]; - if (pv.type != pv2.type) { - ok = false; - break; - } - if (pv.isRValue != pv2.isRValue) { - ok = false; - break; - } - } - } - if (!ok) { - string buf; - llvm::raw_string_ostream ostr(buf); - ostr << "mismatching result types with dispatch"; - ostr << "\n expected "; - unsigned j = 0; - for (; j < result->size(); ++j) { - if (j != 0) ostr << ", "; - ostr << result->values[j].type; - } - ostr << "\n from dispatching to "; - for (j = 0; j < dispatchedTypes.size(); ++j) { - if (j != 0) ostr << ", "; - ostr << dispatchedTypes[j]; + for (unsigned j = 0; j < result2->size(); ++j) { + PVData const &pv = result->values[j]; + PVData const &pv2 = result2->values[j]; + if (pv.type != pv2.type) { + ok = false; + break; } - ostr << "\n but got "; - for (j = 0; j < result->size(); ++j) { - if (j != 0) ostr << ", "; - ostr << result2->values[j].type; + if (pv.isRValue != pv2.isRValue) { + ok = false; + break; } - ostr << "\n when dispatching to " << pvDispatch2.type; - argumentError(index, ostr.str()); } } - dispatchedTypes.push_back(pvDispatch2.type); - } - assert(result.ptr()); - return result; - } - - // - // analyzeCallValue - // - - MultiPValuePtr analyzeCallValue(PVData const &callable, - MultiPValuePtr args) { - switch (callable.type->typeKind) { - case CODE_POINTER_TYPE: - return analyzeCallPointer(callable, args); - default: - break; - } - ObjectPtr obj = unwrapStaticType(callable.type); - if (!obj) { - MultiPValuePtr args2 = new MultiPValue(callable); - args2->add(args); - return analyzeCallValue(staticPValue(operator_call()), args2); - } - - switch (obj->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - case PRIM_OP: { - if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { - PrimOpPtr x = (PrimOp *) obj.ptr(); - return analyzePrimOp(x, args); + if (!ok) { + string buf; + llvm::raw_string_ostream ostr(buf); + ostr << "mismatching result types with dispatch"; + ostr << "\n expected "; + unsigned j = 0; + for (; j < result->size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << result->values[j].type; } - CompileContextPusher pusher(obj, args->values); - InvokeEntry *entry = - analyzeCallable(obj, args->values); - if (entry->callByName) { - ExprListPtr objectExprs = new ExprList(); - for (PVData const *i = args->values.begin(), *end = args->values.end(); - i < end; - ++i) { - objectExprs->add(new ObjectExpr(new PValue(*i))); - } - ExprPtr callableObject = new ObjectExpr(new PValue(callable)); - callableObject->location = topLocation(); - return analyzeCallByName(entry, callableObject, objectExprs, new Env()); - } else if (!entry->analyzed) - return nullptr; - else - return analyzeReturn(entry->returnIsRef, entry->returnTypes); + ostr << "\n from dispatching to "; + for (j = 0; j < dispatchedTypes.size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << dispatchedTypes[j]; + } + ostr << "\n but got "; + for (j = 0; j < result->size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << result2->values[j].type; + } + ostr << "\n when dispatching to " << pvDispatch2.type; + argumentError(index, ostr.str()); } + } + dispatchedTypes.push_back(pvDispatch2.type); + } + assert(result.ptr()); + return result; +} - case INTRINSIC: { - IntrinsicSymbol *intrin = (IntrinsicSymbol *) obj.ptr(); - return analyzeIntrinsic(intrin, args.ptr()); - } +// +// analyzeCallValue +// - default: - error("invalid call expression"); - return nullptr; - } +MultiPValuePtr analyzeCallValue(PVData const &callable, MultiPValuePtr args) { + switch (callable.type->typeKind) { + case CODE_POINTER_TYPE: + return analyzeCallPointer(callable, args); + default: + break; + } + ObjectPtr obj = unwrapStaticType(callable.type); + if (!obj) { + MultiPValuePtr args2 = new MultiPValue(callable); + args2->add(args); + return analyzeCallValue(staticPValue(operator_call()), args2); + } + + switch (obj->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + case PRIM_OP: { + if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { + PrimOpPtr x = (PrimOp *)obj.ptr(); + return analyzePrimOp(x, args); + } + CompileContextPusher pusher(obj, args->values); + InvokeEntry *entry = analyzeCallable(obj, args->values); + if (entry->callByName) { + ExprListPtr objectExprs = new ExprList(); + for (PVData const *i = args->values.begin(), + *end = args->values.end(); + i < end; ++i) { + objectExprs->add(new ObjectExpr(new PValue(*i))); + } + ExprPtr callableObject = new ObjectExpr(new PValue(callable)); + callableObject->location = topLocation(); + return analyzeCallByName(entry, callableObject, objectExprs, + new Env()); + } else if (!entry->analyzed) + return nullptr; + else + return analyzeReturn(entry->returnIsRef, entry->returnTypes); } - - // - // analyzeCallPointer - // - MultiPValuePtr analyzeCallPointer(PVData const &x, - MultiPValuePtr /*args*/) { - switch (x.type->typeKind) { - case CODE_POINTER_TYPE: { - CodePointerType *y = (CodePointerType *) x.type.ptr(); - return analyzeReturn(y->returnIsRef, y->returnTypes); - } + case INTRINSIC: { + IntrinsicSymbol *intrin = (IntrinsicSymbol *)obj.ptr(); + return analyzeIntrinsic(intrin, args.ptr()); + } - default: - assert(false); - return nullptr; - } + default: + error("invalid call expression"); + return nullptr; } +} - // - // analyzeIsDefined, analyzeCallable - // +// +// analyzeCallPointer +// - bool analyzeIsDefined(ObjectPtr x, - llvm::ArrayRef args) { - MatchFailureError failures; - InvokeEntry *entry = lookupInvokeEntry(x, args, failures); +MultiPValuePtr analyzeCallPointer(PVData const &x, MultiPValuePtr /*args*/) { + switch (x.type->typeKind) { + case CODE_POINTER_TYPE: { + CodePointerType *y = (CodePointerType *)x.type.ptr(); + return analyzeReturn(y->returnIsRef, y->returnTypes); + } - if (!entry || !entry->code->hasBody()) - return false; - return true; + default: + assert(false); + return nullptr; } +} - InvokeEntry *analyzeCallable(ObjectPtr x, - llvm::ArrayRef args) { - MatchFailureError failures; - InvokeEntry *entry = lookupInvokeEntry(x, args, failures); +// +// analyzeIsDefined, analyzeCallable +// - if (!entry || !entry->code->hasBody()) { - matchFailureError(failures); - } +bool analyzeIsDefined(ObjectPtr x, llvm::ArrayRef args) { + MatchFailureError failures; + InvokeEntry *entry = lookupInvokeEntry(x, args, failures); - if (entry->parent->shouldLog) - matchFailureLog(failures); + if (!entry || !entry->code->hasBody()) + return false; + return true; +} - if (entry->analyzed) - return entry; - if (entry->analyzing) { - updateAnalysisErrorLocation(); - return entry; - } - if (entry->callByName) { - entry->code = clone(entry->origCode); - return entry; - } +InvokeEntry *analyzeCallable(ObjectPtr x, llvm::ArrayRef args) { + MatchFailureError failures; + InvokeEntry *entry = lookupInvokeEntry(x, args, failures); + + if (!entry || !entry->code->hasBody()) { + matchFailureError(failures); + } - entry->analyzing = true; - analyzeCodeBody(entry); - entry->analyzing = false; + if (entry->parent->shouldLog) + matchFailureLog(failures); + if (entry->analyzed) + return entry; + if (entry->analyzing) { + updateAnalysisErrorLocation(); + return entry; + } + if (entry->callByName) { + entry->code = clone(entry->origCode); return entry; } - // - // analyzeCallByName - // - - MultiPValuePtr analyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - assert(entry->callByName); + entry->analyzing = true; + analyzeCodeBody(entry); + entry->analyzing = false; - CodePtr code = entry->code; - assert(code->body.ptr()); + return entry; +} - if (code->hasReturnSpecs()) { - vector returnIsRef; - vector returnTypes; - evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, - entry->env, returnIsRef, returnTypes); - return analyzeReturn(returnIsRef, returnTypes); +// +// analyzeCallByName +// + +MultiPValuePtr analyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env) { + assert(entry->callByName); + + CodePtr code = entry->code; + assert(code->body.ptr()); + + if (code->hasReturnSpecs()) { + vector returnIsRef; + vector returnTypes; + evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, entry->env, + returnIsRef, returnTypes); + return analyzeReturn(returnIsRef, returnTypes); + } + + if (entry->varArgName.ptr()) + assert(args->size() >= entry->fixedArgNames.size()); + else + assert(args->size() == entry->fixedArgNames.size()); + + EnvPtr bodyEnv = new Env(entry->env); + bodyEnv->callByNameExprHead = callable; + unsigned i = 0; + for (; i < entry->varArgPosition; ++i) { + ExprPtr expr = foreignExpr(env, args->exprs[i]); + addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); + } + if (entry->varArgName.ptr()) { + unsigned j = 0; + const ExprListPtr varArgs = new ExprList(); + for (; j < args->size() - entry->fixedArgNames.size(); ++j) { + ExprPtr expr = foreignExpr(env, args->exprs[i + j]); + varArgs->add(expr); + } + addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); + for (; i < entry->fixedArgNames.size(); ++i) { + ExprPtr expr = foreignExpr(env, args->exprs[i + j]); + addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); } + } - if (entry->varArgName.ptr()) - assert(args->size() >= entry->fixedArgNames.size()); - else - assert(args->size() == entry->fixedArgNames.size()); + AnalysisContext ctx; + StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); + if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) + return nullptr; + if (ctx.returnInitialized) { + return analyzeReturn(ctx.returnIsRef, ctx.returnTypes); + } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { + analysisError(); + return nullptr; + } else { + // assume void return (zero return values) + return new MultiPValue(); + } +} - EnvPtr bodyEnv = new Env(entry->env); - bodyEnv->callByNameExprHead = callable; - unsigned i = 0; - for (; i < entry->varArgPosition; ++i) { - ExprPtr expr = foreignExpr(env, args->exprs[i]); - addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); +// +// analyzeCodeBody +// + +static void unifyInterfaceReturns(InvokeEntry *entry) { + if (entry->parent->callable->objKind == TYPE) { + string buf; + llvm::raw_string_ostream out(buf); + if (entry->returnTypes.size() != 1) { + out << "constructor overload for type " << entry->parent->callable + << " must return a single value of that type"; + error(entry->code, out.str()); } - if (entry->varArgName.ptr()) { - unsigned j = 0; - const ExprListPtr varArgs = new ExprList(); - for (; j < args->size() - entry->fixedArgNames.size(); ++j) { - ExprPtr expr = foreignExpr(env, args->exprs[i + j]); - varArgs->add(expr); - } - addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); - for (; i < entry->fixedArgNames.size(); ++i) { - ExprPtr expr = foreignExpr(env, args->exprs[i + j]); - addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); - } + if (entry->returnIsRef[0]) { + out << "constructor overload for type " << entry->parent->callable + << " must return by value"; + error(entry->code, out.str()); } - - AnalysisContext ctx; - StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); - if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) - return nullptr; - if (ctx.returnInitialized) { - return analyzeReturn(ctx.returnIsRef, ctx.returnTypes); - } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { - analysisError(); - return nullptr; - } else { - // assume void return (zero return values) - return new MultiPValue(); + if (entry->returnTypes[0].ptr() != entry->parent->callable.ptr()) { + out << "constructor overload for type " << entry->parent->callable + << " returns type " << entry->returnTypes[0]; + error(entry->code, out.str()); } + return; } - // - // analyzeCodeBody - // + if (entry->parent->interface == nullptr) + return; + + CodePtr interfaceCode = entry->parent->interface->code; + if (!interfaceCode->returnSpecsDeclared) + return; - static void unifyInterfaceReturns(InvokeEntry *entry) { - if (entry->parent->callable->objKind == TYPE) { + vector interfaceReturnIsRef; + vector interfaceReturnTypes; + + evaluateReturnSpecs(interfaceCode->returnSpecs, + interfaceCode->varReturnSpec, entry->interfaceEnv, + interfaceReturnIsRef, interfaceReturnTypes); + if (entry->returnTypes.size() != interfaceReturnTypes.size()) { + string buf; + llvm::raw_string_ostream out(buf); + out << "interface declares " << interfaceReturnTypes.size() + << " arguments, but got " << entry->returnTypes.size() << "\n" + << " interface at "; + printFileLineCol(out, entry->parent->interface->location); + error(entry->code, out.str()); + } + for (size_t i = 0; i < interfaceReturnTypes.size(); ++i) { + if (interfaceReturnTypes[i] != entry->returnTypes[i]) { string buf; llvm::raw_string_ostream out(buf); - if (entry->returnTypes.size() != 1) { - out << "constructor overload for type " << entry->parent->callable - << " must return a single value of that type"; - error(entry->code, out.str()); - } - if (entry->returnIsRef[0]) { - out << "constructor overload for type " << entry->parent->callable - << " must return by value"; - error(entry->code, out.str()); - } - if (entry->returnTypes[0].ptr() != entry->parent->callable.ptr()) { - out << "constructor overload for type " << entry->parent->callable - << " returns type " << entry->returnTypes[0]; - error(entry->code, out.str()); - } - return; + out << "return value " << i + 1 << ": " + << "interface declares return type " << interfaceReturnTypes[i] + << ", but overload returns type " << entry->returnTypes[i] + << "\n" + << " interface at "; + printFileLineCol(out, entry->parent->interface->location); + error(entry->code, out.str()); } - - if (entry->parent->interface == nullptr) - return; - - CodePtr interfaceCode = entry->parent->interface->code; - if (!interfaceCode->returnSpecsDeclared) - return; - - vector interfaceReturnIsRef; - vector interfaceReturnTypes; - - evaluateReturnSpecs(interfaceCode->returnSpecs, - interfaceCode->varReturnSpec, - entry->interfaceEnv, - interfaceReturnIsRef, interfaceReturnTypes); - if (entry->returnTypes.size() != interfaceReturnTypes.size()) { + if (interfaceReturnIsRef[i] && !entry->returnIsRef[i]) { string buf; llvm::raw_string_ostream out(buf); - out << "interface declares " << interfaceReturnTypes.size() - << " arguments, but got " << entry->returnTypes.size() << "\n" - << " interface at "; + out << "return value " << i + 1 << ": " + << "interface declares return by reference, but overload " + "returns by value\n" + << " interface at "; printFileLineCol(out, entry->parent->interface->location); error(entry->code, out.str()); } - for (size_t i = 0; i < interfaceReturnTypes.size(); ++i) { - if (interfaceReturnTypes[i] != entry->returnTypes[i]) { - string buf; - llvm::raw_string_ostream out(buf); - out << "return value " << i + 1 << ": " - << "interface declares return type " << interfaceReturnTypes[i] - << ", but overload returns type " << entry->returnTypes[i] << "\n" - << " interface at "; - printFileLineCol(out, entry->parent->interface->location); - error(entry->code, out.str()); - } - if (interfaceReturnIsRef[i] && !entry->returnIsRef[i]) { - string buf; - llvm::raw_string_ostream out(buf); - out << "return value " << i + 1 << ": " - << "interface declares return by reference, but overload returns by value\n" - << " interface at "; - printFileLineCol(out, entry->parent->interface->location); - error(entry->code, out.str()); - } - } } +} - void analyzeCodeBody(InvokeEntry *entry) { - assert(!entry->analyzed); +void analyzeCodeBody(InvokeEntry *entry) { + assert(!entry->analyzed); - CodePtr code = entry->code; - assert(code->hasBody()); + CodePtr code = entry->code; + assert(code->hasBody()); - if (code->isLLVMBody() || code->hasReturnSpecs()) { - evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, - entry->env, - entry->returnIsRef, entry->returnTypes); - entry->analyzed = true; - return; - } + if (code->isLLVMBody() || code->hasReturnSpecs()) { + evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, entry->env, + entry->returnIsRef, entry->returnTypes); + entry->analyzed = true; + return; + } - EnvPtr bodyEnv = new Env(entry->env); + EnvPtr bodyEnv = new Env(entry->env); - size_t i = 0; - for (; i < entry->varArgPosition; ++i) { - bool flag = entry->forwardedRValueFlags[i]; - addLocal(bodyEnv, entry->fixedArgNames[i], new PValue(entry->fixedArgTypes[i], flag)); + size_t i = 0; + for (; i < entry->varArgPosition; ++i) { + bool flag = entry->forwardedRValueFlags[i]; + addLocal(bodyEnv, entry->fixedArgNames[i], + new PValue(entry->fixedArgTypes[i], flag)); + } + if (entry->varArgName.ptr()) { + MultiPValuePtr varArgs = new MultiPValue(); + size_t j = 0; + for (; j < entry->varArgTypes.size(); ++j) { + bool flag = entry->forwardedRValueFlags[i + j]; + PVData parg(entry->varArgTypes[j], flag); + varArgs->values.push_back(parg); } - if (entry->varArgName.ptr()) { - MultiPValuePtr varArgs = new MultiPValue(); - size_t j = 0; - for (; j < entry->varArgTypes.size(); ++j) { - bool flag = entry->forwardedRValueFlags[i + j]; - PVData parg(entry->varArgTypes[j], flag); - varArgs->values.push_back(parg); - } - addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); - for (; i < entry->fixedArgNames.size(); ++i) { - bool flag = entry->forwardedRValueFlags[i + j]; - addLocal(bodyEnv, entry->fixedArgNames[i], new PValue(entry->fixedArgTypes[i], flag)); - } + addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); + for (; i < entry->fixedArgNames.size(); ++i) { + bool flag = entry->forwardedRValueFlags[i + j]; + addLocal(bodyEnv, entry->fixedArgNames[i], + new PValue(entry->fixedArgTypes[i], flag)); } + } - AnalysisContext ctx; - StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); - if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) - return; - if (ctx.returnInitialized) { - entry->returnIsRef = ctx.returnIsRef; - entry->returnTypes = ctx.returnTypes; - } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { - analysisError(); - } + AnalysisContext ctx; + StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); + if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) + return; + if (ctx.returnInitialized) { + entry->returnIsRef = ctx.returnIsRef; + entry->returnTypes = ctx.returnTypes; + } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { + analysisError(); + } - unifyInterfaceReturns(entry); + unifyInterfaceReturns(entry); - entry->analyzed = true; - } + entry->analyzed = true; +} - // - // analyzeStatement - // +// +// analyzeStatement +// + +static StatementAnalysis combineStatementAnalysis(StatementAnalysis a, + StatementAnalysis b) { + if ((a == SA_FALLTHROUGH) || (b == SA_FALLTHROUGH)) + return SA_FALLTHROUGH; + if ((a == SA_RECURSIVE) && (b == SA_RECURSIVE)) + return SA_RECURSIVE; + if ((a == SA_TERMINATED) && (b == SA_TERMINATED)) + return SA_TERMINATED; + if ((a == SA_RECURSIVE) && (b == SA_TERMINATED)) + return SA_TERMINATED; + assert((a == SA_TERMINATED) && (b == SA_RECURSIVE)); + return SA_TERMINATED; +} - static StatementAnalysis combineStatementAnalysis(StatementAnalysis a, - StatementAnalysis b) { - if ((a == SA_FALLTHROUGH) || (b == SA_FALLTHROUGH)) - return SA_FALLTHROUGH; - if ((a == SA_RECURSIVE) && (b == SA_RECURSIVE)) +static StatementAnalysis analyzeBlockStatement(const StatementPtr &stmt, + EnvPtr &env, + AnalysisContext *ctx) { + if (stmt->stmtKind == BINDING) { + env = analyzeBinding(static_cast(stmt.ptr()), env); + if (!env) { + ctx->hasRecursivePropagation = true; return SA_RECURSIVE; - if ((a == SA_TERMINATED) && (b == SA_TERMINATED)) - return SA_TERMINATED; - if ((a == SA_RECURSIVE) && (b == SA_TERMINATED)) - return SA_TERMINATED; - assert((a == SA_TERMINATED) && (b == SA_RECURSIVE)); - return SA_TERMINATED; - } + } + return SA_FALLTHROUGH; + } else if (stmt->stmtKind == EVAL_STATEMENT) { + EvalStatement *eval = (EvalStatement *)stmt.ptr(); + llvm::ArrayRef evaled = desugarEvalStatement(eval, env); + for (size_t i = 0; i < evaled.size(); ++i) { + StatementAnalysis sa = analyzeBlockStatement(evaled[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } else + return analyzeStatement(stmt, env, ctx); +} - static StatementAnalysis analyzeBlockStatement(const StatementPtr &stmt, EnvPtr &env, AnalysisContext *ctx) { - if (stmt->stmtKind == BINDING) { - env = analyzeBinding(static_cast(stmt.ptr()), env); - if (!env) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - return SA_FALLTHROUGH; - } else if (stmt->stmtKind == EVAL_STATEMENT) { - EvalStatement *eval = (EvalStatement *) stmt.ptr(); - llvm::ArrayRef evaled = desugarEvalStatement(eval, env); - for (size_t i = 0; i < evaled.size(); ++i) { - StatementAnalysis sa = analyzeBlockStatement(evaled[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } else - return analyzeStatement(stmt, env, ctx); - } - - static EnvPtr analyzeStatementExpressionStatements(llvm::ArrayRef stmts, EnvPtr env) { - EnvPtr env2 = env; - for (StatementPtr const *i = stmts.begin(), *end = stmts.end(); - i != end; - ++i) { - switch ((*i)->stmtKind) { - case BINDING: - env2 = analyzeBinding(static_cast(i->ptr()), env2); - if (env2 == nullptr) - return nullptr; - break; - - case ASSIGNMENT: - case VARIADIC_ASSIGNMENT: - case INIT_ASSIGNMENT: - case EXPR_STATEMENT: - break; - - default: - assert(false); - return nullptr; - } +static EnvPtr +analyzeStatementExpressionStatements(llvm::ArrayRef stmts, + EnvPtr env) { + EnvPtr env2 = env; + for (StatementPtr const *i = stmts.begin(), *end = stmts.end(); i != end; + ++i) { + switch ((*i)->stmtKind) { + case BINDING: + env2 = analyzeBinding(static_cast(i->ptr()), env2); + if (env2 == nullptr) + return nullptr; + break; + + case ASSIGNMENT: + case VARIADIC_ASSIGNMENT: + case INIT_ASSIGNMENT: + case EXPR_STATEMENT: + break; + + default: + assert(false); + return nullptr; } - return env2; } + return env2; +} - static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, AnalysisContext *ctx) { - LocationContext loc(stmt->location); +static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, + AnalysisContext *ctx) { + LocationContext loc(stmt->location); - switch (stmt->stmtKind) { - case BLOCK: { - Block *block = (Block *) stmt.ptr(); - for (size_t i = 0; i < block->statements.size(); ++i) { - StatementAnalysis sa = analyzeBlockStatement(block->statements[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } + switch (stmt->stmtKind) { + case BLOCK: { + Block *block = (Block *)stmt.ptr(); + for (size_t i = 0; i < block->statements.size(); ++i) { + StatementAnalysis sa = + analyzeBlockStatement(block->statements[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case LABEL: - case BINDING: - case ASSIGNMENT: - case INIT_ASSIGNMENT: - case VARIADIC_ASSIGNMENT: - return SA_FALLTHROUGH; + case LABEL: + case BINDING: + case ASSIGNMENT: + case INIT_ASSIGNMENT: + case VARIADIC_ASSIGNMENT: + return SA_FALLTHROUGH; - case GOTO: - return SA_TERMINATED; + case GOTO: + return SA_TERMINATED; - case RETURN: { - Return *x = (Return *) stmt.ptr(); - unsigned wantCount = x->isReturnSpecs ? 1 : 0; - MultiPValuePtr mpv = analyzeMulti(x->values, env, wantCount); + case RETURN: { + Return *x = (Return *)stmt.ptr(); + unsigned wantCount = x->isReturnSpecs ? 1 : 0; + MultiPValuePtr mpv = analyzeMulti(x->values, env, wantCount); - if (!mpv) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - if (ctx->returnInitialized) { - ensureArity(mpv, ctx->returnTypes.size()); - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - bool byRef = returnKindToByRef(x->returnKind, pv); - if (ctx->returnTypes[i] != pv.type) - argumentTypeError(i, ctx->returnTypes[i], pv.type); - if (byRef != ctx->returnIsRef[i]) - argumentError(i, "mismatching by-ref and " - "by-value returns"); - if (byRef && pv.isRValue) - argumentError(i, "cannot return a temporary by reference"); - } - } else { - ctx->returnIsRef.clear(); - ctx->returnTypes.clear(); - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - bool byRef = returnKindToByRef(x->returnKind, pv); - ctx->returnIsRef.push_back(byRef); - if (byRef && pv.isRValue) - argumentError(i, "cannot return a temporary by reference"); - ctx->returnTypes.push_back(pv.type); - } - ctx->returnInitialized = true; - } - return SA_TERMINATED; + if (!mpv) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } + if (ctx->returnInitialized) { + ensureArity(mpv, ctx->returnTypes.size()); + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + bool byRef = returnKindToByRef(x->returnKind, pv); + if (ctx->returnTypes[i] != pv.type) + argumentTypeError(i, ctx->returnTypes[i], pv.type); + if (byRef != ctx->returnIsRef[i]) + argumentError(i, "mismatching by-ref and " + "by-value returns"); + if (byRef && pv.isRValue) + argumentError(i, "cannot return a temporary by reference"); } + } else { + ctx->returnIsRef.clear(); + ctx->returnTypes.clear(); + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + bool byRef = returnKindToByRef(x->returnKind, pv); + ctx->returnIsRef.push_back(byRef); + if (byRef && pv.isRValue) + argumentError(i, "cannot return a temporary by reference"); + ctx->returnTypes.push_back(pv.type); + } + ctx->returnInitialized = true; + } + return SA_TERMINATED; + } - case IF: { - auto x = static_cast(stmt.ptr()); + case IF: { + auto x = static_cast(stmt.ptr()); - EnvPtr env2 = analyzeStatementExpressionStatements(x->conditionStatements, env); - if (env2 == nullptr) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } + EnvPtr env2 = + analyzeStatementExpressionStatements(x->conditionStatements, env); + if (env2 == nullptr) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } - MultiPValuePtr cond = analyzeExpr(x->condition, env2); + MultiPValuePtr cond = analyzeExpr(x->condition, env2); - if (cond->values.size() != 1) { - arityError(1, cond->values.size()); - } + if (cond->values.size() != 1) { + arityError(1, cond->values.size()); + } - PVData &condPvData = cond->values[0]; + PVData &condPvData = cond->values[0]; - BoolKind condKind = typeBoolKind(condPvData.type); + BoolKind condKind = typeBoolKind(condPvData.type); - StatementAnalysis thenResult = SA_FALLTHROUGH; - StatementAnalysis elseResult = SA_FALLTHROUGH; - if (condKind == BOOL_EXPR || condKind == BOOL_STATIC_TRUE) - thenResult = analyzeStatement(x->thenPart, env2, ctx); - if ((condKind == BOOL_EXPR || condKind == BOOL_STATIC_FALSE) && x->elsePart.ptr()) - elseResult = analyzeStatement(x->elsePart, env2, ctx); - return combineStatementAnalysis(thenResult, elseResult); - } + StatementAnalysis thenResult = SA_FALLTHROUGH; + StatementAnalysis elseResult = SA_FALLTHROUGH; + if (condKind == BOOL_EXPR || condKind == BOOL_STATIC_TRUE) + thenResult = analyzeStatement(x->thenPart, env2, ctx); + if ((condKind == BOOL_EXPR || condKind == BOOL_STATIC_FALSE) && + x->elsePart.ptr()) + elseResult = analyzeStatement(x->elsePart, env2, ctx); + return combineStatementAnalysis(thenResult, elseResult); + } - case SWITCH: { - auto *x = static_cast(stmt.ptr()); - if (!x->desugared) - x->desugared = desugarSwitchStatement(x); - return analyzeStatement(x->desugared, env, ctx); - } + case SWITCH: { + auto *x = static_cast(stmt.ptr()); + if (!x->desugared) + x->desugared = desugarSwitchStatement(x); + return analyzeStatement(x->desugared, env, ctx); + } - case EVAL_STATEMENT: { - EvalStatement *eval = (EvalStatement *) stmt.ptr(); - llvm::ArrayRef evaled = desugarEvalStatement(eval, env); - for (size_t i = 0; i < evaled.size(); ++i) { - StatementAnalysis sa = analyzeStatement(evaled[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } + case EVAL_STATEMENT: { + EvalStatement *eval = (EvalStatement *)stmt.ptr(); + llvm::ArrayRef evaled = desugarEvalStatement(eval, env); + for (size_t i = 0; i < evaled.size(); ++i) { + StatementAnalysis sa = analyzeStatement(evaled[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case EXPR_STATEMENT: - return SA_FALLTHROUGH; + case EXPR_STATEMENT: + return SA_FALLTHROUGH; - case WHILE: { - While *x = (While *) stmt.ptr(); + case WHILE: { + While *x = (While *)stmt.ptr(); - EnvPtr env2 = analyzeStatementExpressionStatements(x->conditionStatements, env); - if (env2 == nullptr) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } + EnvPtr env2 = + analyzeStatementExpressionStatements(x->conditionStatements, env); + if (env2 == nullptr) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } - analyzeStatement(x->body, env2, ctx); - return SA_FALLTHROUGH; - } + analyzeStatement(x->body, env2, ctx); + return SA_FALLTHROUGH; + } - case BREAK: - case CONTINUE: - return SA_TERMINATED; + case BREAK: + case CONTINUE: + return SA_TERMINATED; - case FOR: { - For *x = (For *) stmt.ptr(); - if (!x->desugared) - x->desugared = desugarForStatement(x); - return analyzeStatement(x->desugared, env, ctx); - } + case FOR: { + For *x = (For *)stmt.ptr(); + if (!x->desugared) + x->desugared = desugarForStatement(x); + return analyzeStatement(x->desugared, env, ctx); + } - case FOREIGN_STATEMENT: { - ForeignStatement *x = (ForeignStatement *) stmt.ptr(); - return analyzeStatement(x->statement, x->getEnv(), ctx); - } + case FOREIGN_STATEMENT: { + ForeignStatement *x = (ForeignStatement *)stmt.ptr(); + return analyzeStatement(x->statement, x->getEnv(), ctx); + } - case TRY: { - Try *x = (Try *) stmt.ptr(); - if (!exceptionsEnabled()) - return analyzeStatement(x->tryBlock, env, ctx); - if (!x->desugaredCatchBlock) - x->desugaredCatchBlock = desugarCatchBlocks(x->catchBlocks); - StatementAnalysis result1, result2; - result1 = analyzeStatement(x->tryBlock, env, ctx); + case TRY: { + Try *x = (Try *)stmt.ptr(); + if (!exceptionsEnabled()) + return analyzeStatement(x->tryBlock, env, ctx); + if (!x->desugaredCatchBlock) + x->desugaredCatchBlock = desugarCatchBlocks(x->catchBlocks); + StatementAnalysis result1, result2; + result1 = analyzeStatement(x->tryBlock, env, ctx); - EnvPtr catchEnv = new Env(env, true); + EnvPtr catchEnv = new Env(env, true); - result2 = analyzeStatement(x->desugaredCatchBlock, catchEnv, ctx); - return combineStatementAnalysis(result1, result2); - } + result2 = analyzeStatement(x->desugaredCatchBlock, catchEnv, ctx); + return combineStatementAnalysis(result1, result2); + } - case THROW: - return SA_TERMINATED; + case THROW: + return SA_TERMINATED; - case STATIC_FOR: { - StaticFor *x = (StaticFor *) stmt.ptr(); - MultiPValuePtr mpv = analyzeMulti(x->values, env, 2); - if (!mpv) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - initializeStaticForClones(x, mpv->size()); - for (unsigned i = 0; i < mpv->size(); ++i) { - EnvPtr env2 = new Env(env); - addLocal(env2, x->variable, new PValue(mpv->values[i])); - StatementAnalysis sa = analyzeStatement(x->clonedBodies[i], env2, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } + case STATIC_FOR: { + StaticFor *x = (StaticFor *)stmt.ptr(); + MultiPValuePtr mpv = analyzeMulti(x->values, env, 2); + if (!mpv) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } + initializeStaticForClones(x, mpv->size()); + for (unsigned i = 0; i < mpv->size(); ++i) { + EnvPtr env2 = new Env(env); + addLocal(env2, x->variable, new PValue(mpv->values[i])); + StatementAnalysis sa = + analyzeStatement(x->clonedBodies[i], env2, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case FINALLY: - case ONERROR: - return SA_FALLTHROUGH; + case FINALLY: + case ONERROR: + return SA_FALLTHROUGH; - case UNREACHABLE: - return SA_TERMINATED; + case UNREACHABLE: + return SA_TERMINATED; - case STATIC_ASSERT_STATEMENT: - return SA_FALLTHROUGH; + case STATIC_ASSERT_STATEMENT: + return SA_FALLTHROUGH; - default: - assert(false); - return SA_FALLTHROUGH; - } + default: + assert(false); + return SA_FALLTHROUGH; } +} - void initializeStaticForClones(StaticForPtr x, size_t count) { - if (x->clonesInitialized) { - assert(count == x->clonedBodies.size()); - } else { - if (analysisCachingDisabled == 0) - x->clonesInitialized = true; - x->clonedBodies.clear(); - for (unsigned i = 0; i < count; ++i) - x->clonedBodies.push_back(clone(x->body)); - } +void initializeStaticForClones(StaticForPtr x, size_t count) { + if (x->clonesInitialized) { + assert(count == x->clonedBodies.size()); + } else { + if (analysisCachingDisabled == 0) + x->clonesInitialized = true; + x->clonedBodies.clear(); + for (unsigned i = 0; i < count; ++i) + x->clonedBodies.push_back(clone(x->body)); } +} - static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env) { - LocationContext loc(x->location); - - switch (x->bindingKind) { - case VAR: - case REF: - case FORWARD: { - MultiPValuePtr mpv = analyzeMulti(x->values, env, x->args.size()); - if (!mpv) - return nullptr; - - if (x->hasVarArg) { - if (mpv->values.size() < x->args.size() - 1) - arityMismatchError(x->args.size() - 1, mpv->values.size(), /*hasVarArg=*/ true); - } else if (mpv->values.size() != x->args.size()) - arityMismatchError(x->args.size(), mpv->values.size(), /*hasVarArg=*/ false); - - vector key; - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - key.push_back(pv.type); - } +static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env) { + LocationContext loc(x->location); - llvm::ArrayRef pvars = x->patternVars; - EnvPtr patternEnv = new Env(env); - vector cells; - vector multiCells; - initializePatternEnv(patternEnv, pvars, cells, multiCells); - - llvm::ArrayRef formalArgs = x->args; - size_t varArgSize = key.size() - formalArgs.size() + 1; - for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { - FormalArgPtr y = formalArgs[i]; - if (y->varArg) { - if (y->type.ptr()) { - ExprPtr unpack = new Unpack(y->type.ptr()); - unpack->location = y->type->location; - MultiStaticPtr types = new MultiStatic(); - for (; j < varArgSize; ++j) { - types->add(key[i + j].ptr()); - } - --j; - if (!unifyMulti(evaluateMultiPattern(new ExprList(unpack), patternEnv), types)) - matchBindingError(new MatchMultiBindingError(unsigned(formalArgs.size()), types, y)); - } else { - j = varArgSize - 1; - } - } else { - if (y->type.ptr()) { - if (!unifyPatternObj(evaluateOnePattern(y->type, patternEnv), key[i + j].ptr())) - matchBindingError(new MatchBindingError(unsigned(i + j), key[i + j], y)); - } - } - } + switch (x->bindingKind) { + case VAR: + case REF: + case FORWARD: { + MultiPValuePtr mpv = analyzeMulti(x->values, env, x->args.size()); + if (!mpv) + return nullptr; - EnvPtr staticEnv = new Env(env); - for (size_t i = 0; i < pvars.size(); ++i) { - if (pvars[i].isMulti) { - MultiStaticPtr ms = derefDeep(multiCells[i].ptr()); - if (!ms) - error(pvars[i].name, "unbound pattern variable"); - addLocal(staticEnv, pvars[i].name, ms.ptr()); - x->patternTypes.push_back(ms.ptr()); - } else { - ObjectPtr v = derefDeep(cells[i].ptr()); - if (!v) - error(pvars[i].name, "unbound pattern variable"); - addLocal(staticEnv, pvars[i].name, v.ptr()); - x->patternTypes.push_back(v.ptr()); + if (x->hasVarArg) { + if (mpv->values.size() < x->args.size() - 1) + arityMismatchError(x->args.size() - 1, mpv->values.size(), + /*hasVarArg=*/true); + } else if (mpv->values.size() != x->args.size()) + arityMismatchError(x->args.size(), mpv->values.size(), + /*hasVarArg=*/false); + + vector key; + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + key.push_back(pv.type); + } + + llvm::ArrayRef pvars = x->patternVars; + EnvPtr patternEnv = new Env(env); + vector cells; + vector multiCells; + initializePatternEnv(patternEnv, pvars, cells, multiCells); + + llvm::ArrayRef formalArgs = x->args; + size_t varArgSize = key.size() - formalArgs.size() + 1; + for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { + FormalArgPtr y = formalArgs[i]; + if (y->varArg) { + if (y->type.ptr()) { + ExprPtr unpack = new Unpack(y->type.ptr()); + unpack->location = y->type->location; + MultiStaticPtr types = new MultiStatic(); + for (; j < varArgSize; ++j) { + types->add(key[i + j].ptr()); } + --j; + if (!unifyMulti(evaluateMultiPattern(new ExprList(unpack), + patternEnv), + types)) + matchBindingError(new MatchMultiBindingError( + unsigned(formalArgs.size()), types, y)); + } else { + j = varArgSize - 1; } - - evaluatePredicate(x->patternVars, x->predicate, staticEnv); - - EnvPtr env2 = new Env(staticEnv); - for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { - FormalArgPtr y = formalArgs[i]; - if (y->varArg) { - MultiPValuePtr varArgs = new MultiPValue(); - for (; j < varArgSize; ++j) { - PVData parg(key[i + j], false); - varArgs->values.push_back(parg); - } - --j; - addLocal(env2, y->name, varArgs.ptr()); - } else { - addLocal(env2, y->name, new PValue(key[i + j], false)); - } + } else { + if (y->type.ptr()) { + if (!unifyPatternObj( + evaluateOnePattern(y->type, patternEnv), + key[i + j].ptr())) + matchBindingError(new MatchBindingError(unsigned(i + j), + key[i + j], y)); } - return env2; } + } - case ALIAS: { - ensureArity(x->args, 1); - ensureArity(x->values->exprs, 1); - EnvPtr env2 = new Env(env); - ExprPtr y = foreignExpr(env, x->values->exprs[0]); - addLocal(env2, x->args[0]->name, y.ptr()); - return env2; + EnvPtr staticEnv = new Env(env); + for (size_t i = 0; i < pvars.size(); ++i) { + if (pvars[i].isMulti) { + MultiStaticPtr ms = derefDeep(multiCells[i].ptr()); + if (!ms) + error(pvars[i].name, "unbound pattern variable"); + addLocal(staticEnv, pvars[i].name, ms.ptr()); + x->patternTypes.push_back(ms.ptr()); + } else { + ObjectPtr v = derefDeep(cells[i].ptr()); + if (!v) + error(pvars[i].name, "unbound pattern variable"); + addLocal(staticEnv, pvars[i].name, v.ptr()); + x->patternTypes.push_back(v.ptr()); } + } - default: - assert(false); - return nullptr; + evaluatePredicate(x->patternVars, x->predicate, staticEnv); + + EnvPtr env2 = new Env(staticEnv); + for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { + FormalArgPtr y = formalArgs[i]; + if (y->varArg) { + MultiPValuePtr varArgs = new MultiPValue(); + for (; j < varArgSize; ++j) { + PVData parg(key[i + j], false); + varArgs->values.push_back(parg); + } + --j; + addLocal(env2, y->name, varArgs.ptr()); + } else { + addLocal(env2, y->name, new PValue(key[i + j], false)); + } } + return env2; } - bool returnKindToByRef(ReturnKind returnKind, PVData const &pv) { - switch (returnKind) { - case RETURN_VALUE: return false; - case RETURN_REF: return true; - case RETURN_FORWARD: return !pv.isRValue; - default: assert(false); - return false; - } + case ALIAS: { + ensureArity(x->args, 1); + ensureArity(x->values->exprs, 1); + EnvPtr env2 = new Env(env); + ExprPtr y = foreignExpr(env, x->values->exprs[0]); + addLocal(env2, x->args[0]->name, y.ptr()); + return env2; } - BoolKind typeBoolKind(TypePtr type) { - if (type == boolType) { - return BOOL_EXPR; - } else if (type->typeKind == STATIC_TYPE) { - StaticType *staticType = (StaticType *) type.ptr(); - if (staticType->obj->objKind != VALUE_HOLDER) { - error("expecting value holder"); - } - ValueHolder *valueHolder = (ValueHolder *) staticType->obj.ptr(); - if (valueHolder->type != boolType) { - typeError(boolType, valueHolder->type); - } - bool staticValue = valueHolder->as(); - return staticValue ? BOOL_STATIC_TRUE : BOOL_STATIC_FALSE; - } else { - typeError("Bool or static Bool", type); - return BOOL_STATIC_TRUE; - } + default: + assert(false); + return nullptr; } +} - ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs) { - if (wantCount >= 1 && exprs->size() == 1 && exprs->exprs[0]->exprKind != UNPACK) - return exprs->exprs[0]; - else - return nullptr; +bool returnKindToByRef(ReturnKind returnKind, PVData const &pv) { + switch (returnKind) { + case RETURN_VALUE: + return false; + case RETURN_REF: + return true; + case RETURN_FORWARD: + return !pv.isRValue; + default: + assert(false); + return false; + } +} + +BoolKind typeBoolKind(TypePtr type) { + if (type == boolType) { + return BOOL_EXPR; + } else if (type->typeKind == STATIC_TYPE) { + StaticType *staticType = (StaticType *)type.ptr(); + if (staticType->obj->objKind != VALUE_HOLDER) { + error("expecting value holder"); + } + ValueHolder *valueHolder = (ValueHolder *)staticType->obj.ptr(); + if (valueHolder->type != boolType) { + typeError(boolType, valueHolder->type); + } + bool staticValue = valueHolder->as(); + return staticValue ? BOOL_STATIC_TRUE : BOOL_STATIC_FALSE; + } else { + typeError("Bool or static Bool", type); + return BOOL_STATIC_TRUE; } } + +ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs) { + if (wantCount >= 1 && exprs->size() == 1 && + exprs->exprs[0]->exprKind != UNPACK) + return exprs->exprs[0]; + else + return nullptr; +} +} // namespace clay diff --git a/compiler/analyzer.hpp b/compiler/analyzer.hpp index f2ee6e91..81940127 100644 --- a/compiler/analyzer.hpp +++ b/compiler/analyzer.hpp @@ -2,140 +2,109 @@ #include "clay.hpp" -// #include "invoketables.hpp" +#include "invoketables.hpp" #include "types.hpp" namespace clay { - void disableAnalysisCaching(); - void enableAnalysisCaching(); - - struct AnalysisCachingDisabler { - AnalysisCachingDisabler() { disableAnalysisCaching(); } - ~AnalysisCachingDisabler() { enableAnalysisCaching(); } - }; - - void initializeStaticForClones(StaticForPtr x, size_t count); - bool returnKindToByRef(ReturnKind returnKind, PVData const &pv); - - ObjectPtr unwrapStaticType(TypePtr t); - - bool staticToBool(ObjectPtr x, bool &out, TypePtr &type); - bool staticToBool(MultiStaticPtr x, unsigned index); - bool staticToCallingConv(ObjectPtr x, CallingConv &out); - CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index); - - static inline PVData staticPValue(ObjectPtr x) { - const TypePtr t = staticType(x); - return PVData(t, true); - } - - enum BoolKind { - BOOL_EXPR, - BOOL_STATIC_TRUE, - BOOL_STATIC_FALSE - }; - - BoolKind typeBoolKind(TypePtr type); - - PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env); - MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); - MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env); - MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices); - InvokeEntry *safeAnalyzeCallable(ObjectPtr x, - llvm::ArrayRef args); - MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x); - - MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); - PVData analyzeOne(ExprPtr expr, EnvPtr env); - - MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices); - PVData analyzeOneArg(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); - MultiPValuePtr analyzeArgExpr(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); - - MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env); - MultiPValuePtr analyzeStaticObject(ObjectPtr x); - - GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, - llvm::ArrayRef params); - GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x); - GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x); - - PVData analyzeExternalVariable(ExternalVariablePtr x); - void analyzeExternalProcedure(ExternalProcedurePtr x); - void verifyAttributes(ExternalProcedurePtr x); - void verifyAttributes(ExternalVariablePtr x); - void verifyAttributes(ModulePtr x); - MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, +void disableAnalysisCaching(); +void enableAnalysisCaching(); + +struct AnalysisCachingDisabler { + AnalysisCachingDisabler() { disableAnalysisCaching(); } + ~AnalysisCachingDisabler() { enableAnalysisCaching(); } +}; + +void initializeStaticForClones(StaticForPtr x, size_t count); +bool returnKindToByRef(ReturnKind returnKind, PVData const &pv); + +ObjectPtr unwrapStaticType(TypePtr t); + +bool staticToBool(ObjectPtr x, bool &out, TypePtr &type); +bool staticToBool(MultiStaticPtr x, unsigned index); +bool staticToCallingConv(ObjectPtr x, CallingConv &out); +CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index); + +static PVData staticPValue(const ObjectPtr &x) { + const TypePtr t = staticType(x); + return {t, true}; +} + +enum BoolKind { BOOL_EXPR, BOOL_STATIC_TRUE, BOOL_STATIC_FALSE }; + +BoolKind typeBoolKind(TypePtr type); + +PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env); +MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, + size_t wantCount); +MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env); +MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, EnvPtr env); - bool unwrapByRef(TypePtr &t); - TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args); - PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args); - MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, - llvm::ArrayRef returnTypes); - MultiPValuePtr analyzeCallExpr(ExprPtr callable, - ExprListPtr args, +MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices); +InvokeEntry *safeAnalyzeCallable(ObjectPtr x, llvm::ArrayRef args); +MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env); +MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x); + +MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); +PVData analyzeOne(ExprPtr expr, EnvPtr env); + +MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices); +PVData analyzeOneArg(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices); +MultiPValuePtr analyzeArgExpr(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices); + +MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env); +MultiPValuePtr analyzeStaticObject(ObjectPtr x); + +GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, + llvm::ArrayRef params); +GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x); +GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, ExprListPtr args, + EnvPtr env); +MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x); + +PVData analyzeExternalVariable(ExternalVariablePtr x); +void analyzeExternalProcedure(ExternalProcedurePtr x); +void verifyAttributes(ExternalProcedurePtr x); +void verifyAttributes(ExternalVariablePtr x); +void verifyAttributes(ModulePtr x); +MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, EnvPtr env); - PVData analyzeDispatchIndex(PVData const &pv, unsigned tag); - MultiPValuePtr analyzeDispatch(ObjectPtr obj, - MultiPValuePtr args, - llvm::ArrayRef dispatchIndices); - MultiPValuePtr analyzeCallValue(PVData const &callable, - MultiPValuePtr args); - MultiPValuePtr analyzeCallPointer(PVData const &x, - MultiPValuePtr args); - bool analyzeIsDefined(ObjectPtr x, - llvm::ArrayRef args); - InvokeEntry *analyzeCallable(ObjectPtr x, - llvm::ArrayRef args); - - MultiPValuePtr analyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env); - - void analyzeCodeBody(InvokeEntry *entry); - - struct AnalysisContext { - vector returnIsRef; - vector returnTypes; - bool hasRecursivePropagation: 1; - bool returnInitialized: 1; - - AnalysisContext() - : hasRecursivePropagation(false), - returnInitialized(false) { - } - }; - - enum StatementAnalysis { - SA_FALLTHROUGH, - SA_RECURSIVE, - SA_TERMINATED - }; - - ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs); -} +bool unwrapByRef(TypePtr &t); +TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args); +PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args); +MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, ExprListPtr args, + EnvPtr env); +MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, + llvm::ArrayRef returnTypes); +MultiPValuePtr analyzeCallExpr(ExprPtr callable, ExprListPtr args, EnvPtr env); +PVData analyzeDispatchIndex(PVData const &pv, unsigned tag); +MultiPValuePtr analyzeDispatch(ObjectPtr obj, MultiPValuePtr args, + llvm::ArrayRef dispatchIndices); +MultiPValuePtr analyzeCallValue(PVData const &callable, MultiPValuePtr args); +MultiPValuePtr analyzeCallPointer(PVData const &x, MultiPValuePtr args); +bool analyzeIsDefined(ObjectPtr x, llvm::ArrayRef args); +InvokeEntry *analyzeCallable(ObjectPtr x, llvm::ArrayRef args); + +MultiPValuePtr analyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env); + +void analyzeCodeBody(InvokeEntry *entry); + +struct AnalysisContext { + vector returnIsRef; + vector returnTypes; + bool hasRecursivePropagation : 1; + bool returnInitialized : 1; + + AnalysisContext() + : hasRecursivePropagation(false), returnInitialized(false) {} +}; + +enum StatementAnalysis { SA_FALLTHROUGH, SA_RECURSIVE, SA_TERMINATED }; + +ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs); +} // namespace clay diff --git a/compiler/analyzer_op.cpp b/compiler/analyzer_op.cpp index 792e28b5..c93a66a1 100644 --- a/compiler/analyzer_op.cpp +++ b/compiler/analyzer_op.cpp @@ -1,1061 +1,1053 @@ +#include "analyzer_op.hpp" +#include "analyzer.hpp" +#include "constructors.hpp" +#include "env.hpp" #include "error.hpp" -#include "objects.hpp" #include "evaluator.hpp" -#include "constructors.hpp" +#include "invoketables.hpp" #include "loader.hpp" -#include "env.hpp" - -#include "analyzer.hpp" - -#include "analyzer_op.hpp" +#include "objects.hpp" namespace clay { - static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { - ObjectPtr obj = unwrapStaticType(args->values[index].type); - if (obj->objKind == VALUE_HOLDER) { - ValueHolderPtr vh = (ValueHolder *) obj.ptr(); - if (vh->type == cSizeTType) { - return *((size_t *) vh->buf); - } else if (vh->type == cIntType) { - return (size_t) *((int *) vh->buf); - } - } - argumentError(index, "expecting static SizeT or Int value", args->values[index]); - } - - static TypePtr numericTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - switch (t->typeKind) { - case INTEGER_TYPE: - case FLOAT_TYPE: - return t; - default: - argumentTypeError(index, "numeric type", t); - return nullptr; +static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { + ObjectPtr obj = unwrapStaticType(args->values[index].type); + if (obj->objKind == VALUE_HOLDER) { + ValueHolderPtr vh = (ValueHolder *)obj.ptr(); + if (vh->type == cSizeTType) { + return *((size_t *)vh->buf); + } else if (vh->type == cIntType) { + return (size_t)*((int *)vh->buf); } } + argumentError(index, "expecting static SizeT or Int value", + args->values[index]); +} - static IntegerTypePtr integerTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != INTEGER_TYPE) - argumentTypeError(index, "integer type", t); - return (IntegerType *) t.ptr(); +static TypePtr numericTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + switch (t->typeKind) { + case INTEGER_TYPE: + case FLOAT_TYPE: + return t; + default: + argumentTypeError(index, "numeric type", t); + return nullptr; } +} - static PointerTypePtr pointerTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != POINTER_TYPE) - argumentTypeError(index, "pointer type", t); - return (PointerType *) t.ptr(); - } +static IntegerTypePtr integerTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != INTEGER_TYPE) + argumentTypeError(index, "integer type", t); + return (IntegerType *)t.ptr(); +} - static CCodePointerTypePtr cCodePointerTypeOfValue(MultiPValuePtr x, - unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != CCODE_POINTER_TYPE) - argumentTypeError(index, "external code pointer type", t); - return (CCodePointerType *) t.ptr(); - } +static PointerTypePtr pointerTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != POINTER_TYPE) + argumentTypeError(index, "pointer type", t); + return (PointerType *)t.ptr(); +} - static ArrayTypePtr arrayTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != ARRAY_TYPE) - argumentTypeError(index, "array type", t); - return (ArrayType *) t.ptr(); - } +static CCodePointerTypePtr cCodePointerTypeOfValue(MultiPValuePtr x, + unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != CCODE_POINTER_TYPE) + argumentTypeError(index, "external code pointer type", t); + return (CCodePointerType *)t.ptr(); +} - static TupleTypePtr tupleTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != TUPLE_TYPE) - argumentTypeError(index, "tuple type", t); - return (TupleType *) t.ptr(); - } +static ArrayTypePtr arrayTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != ARRAY_TYPE) + argumentTypeError(index, "array type", t); + return (ArrayType *)t.ptr(); +} - static RecordTypePtr recordTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != RECORD_TYPE) - argumentTypeError(index, "record type", t); - return (RecordType *) t.ptr(); - } +static TupleTypePtr tupleTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != TUPLE_TYPE) + argumentTypeError(index, "tuple type", t); + return (TupleType *)t.ptr(); +} - static TypePtr valueToType(MultiPValuePtr x, unsigned index) { - ObjectPtr obj = unwrapStaticType(x->values[index].type); - if (!obj) - argumentError(index, "expecting a type"); - TypePtr t; - if (!staticToType(obj, t)) - argumentError(index, "expecting a type"); +static RecordTypePtr recordTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != RECORD_TYPE) + argumentTypeError(index, "record type", t); + return (RecordType *)t.ptr(); +} + +static TypePtr valueToType(MultiPValuePtr x, unsigned index) { + ObjectPtr obj = unwrapStaticType(x->values[index].type); + if (!obj) + argumentError(index, "expecting a type"); + TypePtr t; + if (!staticToType(obj, t)) + argumentError(index, "expecting a type"); + return t; +} + +static TypePtr valueToNumericType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + switch (t->typeKind) { + case INTEGER_TYPE: + case FLOAT_TYPE: return t; + default: + argumentTypeError(index, "numeric type", t); + return nullptr; } +} - static TypePtr valueToNumericType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - switch (t->typeKind) { - case INTEGER_TYPE: - case FLOAT_TYPE: - return t; - default: - argumentTypeError(index, "numeric type", t); - return nullptr; - } - } +static IntegerTypePtr valueToIntegerType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (t->typeKind != INTEGER_TYPE) + argumentTypeError(index, "integer type", t); + return (IntegerType *)t.ptr(); +} + +static TypePtr valueToPointerLikeType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (!isPointerOrCodePointerType(t)) + argumentTypeError(index, "pointer or code-pointer type", t); + return t; +} - static IntegerTypePtr valueToIntegerType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (t->typeKind != INTEGER_TYPE) - argumentTypeError(index, "integer type", t); - return (IntegerType *) t.ptr(); +static EnumTypePtr valueToEnumType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (t->typeKind != ENUM_TYPE) + argumentTypeError(index, "enum type", t); + return (EnumType *)t.ptr(); +} + +static std::pair, InvokeEntry *> +invokeEntryForCallableArguments(MultiPValuePtr args, unsigned callableIndex, + unsigned firstArgTypeIndex) { + if (args->size() < firstArgTypeIndex) + arityError2(firstArgTypeIndex, args->size()); + ObjectPtr callable = unwrapStaticType(args->values[callableIndex].type); + if (!callable) + argumentError(callableIndex, "static callable expected"); + switch (callable->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + break; + case PRIM_OP: + if (!isOverloadablePrimOp(callable)) + argumentError(callableIndex, "invalid callable"); + break; + default: + argumentError(callableIndex, "invalid callable"); + } + vector argTypes; + vector argsPVData; + for (unsigned i = firstArgTypeIndex; i < args->size(); ++i) { + TypePtr t = valueToType(args, i); + argTypes.push_back(t); + argsPVData.push_back(PVData(t, false)); } - static TypePtr valueToPointerLikeType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (!isPointerOrCodePointerType(t)) - argumentTypeError(index, "pointer or code-pointer type", t); - return t; + CompileContextPusher pusher(callable, argsPVData); + + return std::make_pair(argTypes, analyzeCallable(callable, argsPVData)); +} + +MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args) { + switch (x->primOpCode) { + case PRIM_TypeP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_TypeSize: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_TypeAlignment: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_OperatorP: + case PRIM_SymbolP: + case PRIM_StaticCallDefinedP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_StaticCallOutputTypes: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < entry.second->returnTypes.size(); ++i) + values->add(staticPValue(entry.second->returnTypes[i].ptr())); + return values; } - static EnumTypePtr valueToEnumType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (t->typeKind != ENUM_TYPE) - argumentTypeError(index, "enum type", t); - return (EnumType *) t.ptr(); + case PRIM_StaticMonoP: { + return new MultiPValue(PVData(boolType, true)); } - static std::pair, InvokeEntry *> - invokeEntryForCallableArguments(MultiPValuePtr args, unsigned callableIndex, unsigned firstArgTypeIndex) { - if (args->size() < firstArgTypeIndex) - arityError2(firstArgTypeIndex, args->size()); - ObjectPtr callable = unwrapStaticType(args->values[callableIndex].type); + case PRIM_StaticMonoInputTypes: { + ensureArity(args, 1); + ObjectPtr callable = unwrapStaticType(args->values[0].type); if (!callable) - argumentError(callableIndex, "static callable expected"); + argumentError(0, "static callable expected"); + switch (callable->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - break; - case PRIM_OP: - if (!isOverloadablePrimOp(callable)) - argumentError(callableIndex, "invalid callable"); - break; - default: - argumentError(callableIndex, "invalid callable"); + case PROCEDURE: { + Procedure *proc = (Procedure *)callable.ptr(); + if (proc->mono.monoState != Procedure_MonoOverload) { + argumentError(0, "not a static monomorphic callable"); + } + + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < proc->mono.monoTypes.size(); ++i) + values->add(staticPValue(proc->mono.monoTypes[i].ptr())); + + return values; } - vector argTypes; - vector argsPVData; - for (unsigned i = firstArgTypeIndex; i < args->size(); ++i) { - TypePtr t = valueToType(args, i); - argTypes.push_back(t); - argsPVData.push_back(PVData(t, false)); + + default: + argumentError(0, "not a static monomorphic callable"); } + } - CompileContextPusher pusher(callable, argsPVData); + case PRIM_bitcopy: + return new MultiPValue(); + + case PRIM_boolNot: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_integerEqualsP: + case PRIM_integerLesserP: + case PRIM_floatOrderedEqualsP: + case PRIM_floatOrderedLesserP: + case PRIM_floatOrderedLesserEqualsP: + case PRIM_floatOrderedGreaterP: + case PRIM_floatOrderedGreaterEqualsP: + case PRIM_floatOrderedNotEqualsP: + case PRIM_floatOrderedP: + case PRIM_floatUnorderedEqualsP: + case PRIM_floatUnorderedLesserP: + case PRIM_floatUnorderedLesserEqualsP: + case PRIM_floatUnorderedGreaterP: + case PRIM_floatUnorderedGreaterEqualsP: + case PRIM_floatUnorderedNotEqualsP: + case PRIM_floatUnorderedP: + ensureArity(args, 2); + return new MultiPValue(PVData(boolType, true)); + + case PRIM_numericAdd: + case PRIM_numericSubtract: + case PRIM_numericMultiply: + case PRIM_floatDivide: { + ensureArity(args, 2); + TypePtr t = numericTypeOfValue(args, 0); + return new MultiPValue(PVData(t, true)); + } - return std::make_pair( - argTypes, - analyzeCallable(callable, argsPVData)); + case PRIM_numericNegate: { + ensureArity(args, 1); + TypePtr t = numericTypeOfValue(args, 0); + return new MultiPValue(PVData(t, true)); } - MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args) { - switch (x->primOpCode) { - case PRIM_TypeP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_integerQuotient: + case PRIM_integerRemainder: + case PRIM_integerShiftLeft: + case PRIM_integerShiftRight: + case PRIM_integerBitwiseAnd: + case PRIM_integerBitwiseOr: + case PRIM_integerBitwiseXor: + case PRIM_integerAddChecked: + case PRIM_integerSubtractChecked: + case PRIM_integerMultiplyChecked: + case PRIM_integerQuotientChecked: + case PRIM_integerRemainderChecked: + case PRIM_integerShiftLeftChecked: { + ensureArity(args, 2); + IntegerTypePtr t = integerTypeOfValue(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_TypeSize: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_integerBitwiseNot: + case PRIM_integerNegateChecked: { + ensureArity(args, 1); + IntegerTypePtr t = integerTypeOfValue(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_TypeAlignment: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_numericConvert: { + ensureArity(args, 2); + TypePtr t = valueToNumericType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_OperatorP: - case PRIM_SymbolP: - case PRIM_StaticCallDefinedP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_integerConvertChecked: { + ensureArity(args, 2); + IntegerTypePtr t = valueToIntegerType(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_StaticCallOutputTypes: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < entry.second->returnTypes.size(); ++i) - values->add(staticPValue(entry.second->returnTypes[i].ptr())); - return values; - } + case PRIM_Pointer: + error("no Pointer type constructor overload found"); - case PRIM_StaticMonoP: { - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_addressOf: { + ensureArity(args, 1); + TypePtr t = pointerType(args->values[0].type); + return new MultiPValue(PVData(t, true)); + } - case PRIM_StaticMonoInputTypes: { - ensureArity(args, 1); - ObjectPtr callable = unwrapStaticType(args->values[0].type); - if (!callable) - argumentError(0, "static callable expected"); - - switch (callable->objKind) { - case PROCEDURE: { - Procedure *proc = (Procedure *) callable.ptr(); - if (proc->mono.monoState != Procedure_MonoOverload) { - argumentError(0, "not a static monomorphic callable"); - } - - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < proc->mono.monoTypes.size(); ++i) - values->add(staticPValue(proc->mono.monoTypes[i].ptr())); - - return values; - } - - default: - argumentError(0, "not a static monomorphic callable"); - } - } + case PRIM_pointerDereference: { + ensureArity(args, 1); + PointerTypePtr pt = pointerTypeOfValue(args, 0); + return new MultiPValue(PVData(pt->pointeeType, false)); + } - case PRIM_bitcopy: - return new MultiPValue(); - - case PRIM_boolNot: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_integerEqualsP: - case PRIM_integerLesserP: - case PRIM_floatOrderedEqualsP: - case PRIM_floatOrderedLesserP: - case PRIM_floatOrderedLesserEqualsP: - case PRIM_floatOrderedGreaterP: - case PRIM_floatOrderedGreaterEqualsP: - case PRIM_floatOrderedNotEqualsP: - case PRIM_floatOrderedP: - case PRIM_floatUnorderedEqualsP: - case PRIM_floatUnorderedLesserP: - case PRIM_floatUnorderedLesserEqualsP: - case PRIM_floatUnorderedGreaterP: - case PRIM_floatUnorderedGreaterEqualsP: - case PRIM_floatUnorderedNotEqualsP: - case PRIM_floatUnorderedP: - ensureArity(args, 2); - return new MultiPValue(PVData(boolType, true)); - - case PRIM_numericAdd: - case PRIM_numericSubtract: - case PRIM_numericMultiply: - case PRIM_floatDivide: { - ensureArity(args, 2); - TypePtr t = numericTypeOfValue(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_pointerOffset: { + ensureArity(args, 2); + PointerTypePtr pt = pointerTypeOfValue(args, 0); + return new MultiPValue(PVData(pt.ptr(), true)); + } - case PRIM_numericNegate: { - ensureArity(args, 1); - TypePtr t = numericTypeOfValue(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_pointerToInt: { + ensureArity(args, 2); + IntegerTypePtr t = valueToIntegerType(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_integerQuotient: - case PRIM_integerRemainder: - case PRIM_integerShiftLeft: - case PRIM_integerShiftRight: - case PRIM_integerBitwiseAnd: - case PRIM_integerBitwiseOr: - case PRIM_integerBitwiseXor: - case PRIM_integerAddChecked: - case PRIM_integerSubtractChecked: - case PRIM_integerMultiplyChecked: - case PRIM_integerQuotientChecked: - case PRIM_integerRemainderChecked: - case PRIM_integerShiftLeftChecked: { - ensureArity(args, 2); - IntegerTypePtr t = integerTypeOfValue(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_intToPointer: { + ensureArity(args, 2); + TypePtr t = valueToPointerLikeType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_integerBitwiseNot: - case PRIM_integerNegateChecked: { - ensureArity(args, 1); - IntegerTypePtr t = integerTypeOfValue(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_nullPointer: { + ensureArity(args, 1); + TypePtr t = valueToPointerLikeType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_numericConvert: { - ensureArity(args, 2); - TypePtr t = valueToNumericType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_CodePointer: + error("no CodePointer type constructor overload found"); + + case PRIM_makeCodePointer: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); + if (entry.second->callByName) + argumentError(0, "cannot create pointer to call-by-name code"); + if (!entry.second->analyzed) + return nullptr; + TypePtr cpType = codePointerType(entry.first, entry.second->returnIsRef, + entry.second->returnTypes); + return new MultiPValue(PVData(cpType, true)); + } - case PRIM_integerConvertChecked: { - ensureArity(args, 2); - IntegerTypePtr t = valueToIntegerType(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_ExternalCodePointer: + error("no ExternalCodePointer type constructor overload found"); + + case PRIM_makeExternalCodePointer: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 3); + if (entry.second->callByName) + argumentError(0, "cannot create pointer to call-by-name code"); + if (!entry.second->analyzed) + return nullptr; + + ObjectPtr ccObj = unwrapStaticType(args->values[1].type); + CallingConv cc; + if (!staticToCallingConv(ccObj, cc)) + argumentError(1, "expecting a calling convention attribute"); + + ObjectPtr isVarArgObj = unwrapStaticType(args->values[2].type); + bool isVarArg; + TypePtr type; + if (!staticToBool(isVarArgObj, isVarArg, type)) + argumentTypeError(2, "static Bool", type); + + if (isVarArg) + argumentError(2, "implementation of external variadic functions is " + "not yet supported"); + + TypePtr returnType; + if (entry.second->returnTypes.empty()) { + returnType = nullptr; + } else if (entry.second->returnTypes.size() == 1) { + if (entry.second->returnIsRef[0]) { + argumentError(0, "cannot create external code pointer to " + " return-by-reference code"); + } + returnType = entry.second->returnTypes[0]; + } else { + argumentError(0, "cannot create external code pointer to " + "multi-return code"); + } + TypePtr ccpType = + cCodePointerType(cc, entry.first, isVarArg, returnType); + return new MultiPValue(PVData(ccpType, true)); + } - case PRIM_Pointer: - error("no Pointer type constructor overload found"); + case PRIM_callExternalCodePointer: { + if (args->size() < 1) + arityError2(1, args->size()); + CCodePointerTypePtr y = cCodePointerTypeOfValue(args, 0); + if (!y->returnType) + return new MultiPValue(); + return new MultiPValue(PVData(y->returnType, true)); + } - case PRIM_addressOf: { - ensureArity(args, 1); - TypePtr t = pointerType(args->values[0].type); - return new MultiPValue(PVData(t, true)); - } + case PRIM_bitcast: { + ensureArity(args, 2); + TypePtr t = valueToType(args, 0); + return new MultiPValue(PVData(t, false)); + } - case PRIM_pointerDereference: { - ensureArity(args, 1); - PointerTypePtr pt = pointerTypeOfValue(args, 0); - return new MultiPValue(PVData(pt->pointeeType, false)); - } + case PRIM_Array: + error("no Array type constructor overload found"); - case PRIM_pointerOffset: { - ensureArity(args, 2); - PointerTypePtr pt = pointerTypeOfValue(args, 0); - return new MultiPValue(PVData(pt.ptr(), true)); - } + case PRIM_arrayRef: { + ensureArity(args, 2); + ArrayTypePtr t = arrayTypeOfValue(args, 0); + return new MultiPValue(PVData(t->elementType, false)); + } - case PRIM_pointerToInt: { - ensureArity(args, 2); - IntegerTypePtr t = valueToIntegerType(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_arrayElements: { + ensureArity(args, 1); + ArrayTypePtr t = arrayTypeOfValue(args, 0); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < t->size; ++i) + mpv->add(PVData(t->elementType, false)); + return mpv; + } - case PRIM_intToPointer: { - ensureArity(args, 2); - TypePtr t = valueToPointerLikeType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_Vec: + error("no Vec type constructor overload found"); - case PRIM_nullPointer: { - ensureArity(args, 1); - TypePtr t = valueToPointerLikeType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_Tuple: + error("no Tuple type constructor overload found"); - case PRIM_CodePointer: - error("no CodePointer type constructor overload found"); - - case PRIM_makeCodePointer: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - if (entry.second->callByName) - argumentError(0, "cannot create pointer to call-by-name code"); - if (!entry.second->analyzed) - return nullptr; - TypePtr cpType = codePointerType(entry.first, - entry.second->returnIsRef, - entry.second->returnTypes); - return new MultiPValue(PVData(cpType, true)); - } + case PRIM_TupleElementCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_ExternalCodePointer: - error("no ExternalCodePointer type constructor overload found"); - - case PRIM_makeExternalCodePointer: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 3); - if (entry.second->callByName) - argumentError(0, "cannot create pointer to call-by-name code"); - if (!entry.second->analyzed) - return nullptr; - - ObjectPtr ccObj = unwrapStaticType(args->values[1].type); - CallingConv cc; - if (!staticToCallingConv(ccObj, cc)) - argumentError(1, "expecting a calling convention attribute"); - - ObjectPtr isVarArgObj = unwrapStaticType(args->values[2].type); - bool isVarArg; - TypePtr type; - if (!staticToBool(isVarArgObj, isVarArg, type)) - argumentTypeError(2, "static Bool", type); - - if (isVarArg) - argumentError(2, "implementation of external variadic functions is not yet supported"); - - TypePtr returnType; - if (entry.second->returnTypes.empty()) { - returnType = nullptr; - } else if (entry.second->returnTypes.size() == 1) { - if (entry.second->returnIsRef[0]) { - argumentError(0, "cannot create external code pointer to " - " return-by-reference code"); - } - returnType = entry.second->returnTypes[0]; - } else { - argumentError(0, "cannot create external code pointer to " - "multi-return code"); - } - TypePtr ccpType = cCodePointerType(cc, - entry.first, - isVarArg, - returnType); - return new MultiPValue(PVData(ccpType, true)); - } + case PRIM_tupleRef: { + ensureArity(args, 2); + TupleTypePtr t = tupleTypeOfValue(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + if (i >= t->elementTypes.size()) + argumentIndexRangeError(1, "tuple element index", i, + t->elementTypes.size()); + return new MultiPValue(PVData(t->elementTypes[i], false)); + } - case PRIM_callExternalCodePointer: { - if (args->size() < 1) - arityError2(1, args->size()); - CCodePointerTypePtr y = cCodePointerTypeOfValue(args, 0); - if (!y->returnType) - return new MultiPValue(); - return new MultiPValue(PVData(y->returnType, true)); - } + case PRIM_tupleElements: { + ensureArity(args, 1); + TupleTypePtr t = tupleTypeOfValue(args, 0); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < t->elementTypes.size(); ++i) + mpv->add(PVData(t->elementTypes[i], false)); + return mpv; + } - case PRIM_bitcast: { - ensureArity(args, 2); - TypePtr t = valueToType(args, 0); - return new MultiPValue(PVData(t, false)); - } + case PRIM_Union: + error("no Union type constructor overload found"); - case PRIM_Array: - error("no Array type constructor overload found"); + case PRIM_UnionMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_arrayRef: { - ensureArity(args, 2); - ArrayTypePtr t = arrayTypeOfValue(args, 0); - return new MultiPValue(PVData(t->elementType, false)); - } + case PRIM_RecordP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_arrayElements: { - ensureArity(args, 1); - ArrayTypePtr t = arrayTypeOfValue(args, 0); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < t->size; ++i) - mpv->add(PVData(t->elementType, false)); - return mpv; - } + case PRIM_RecordFieldCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_Vec: - error("no Vec type constructor overload found"); + case PRIM_RecordFieldName: { + ensureArity(args, 2); + ObjectPtr first = unwrapStaticType(args->values[0].type); + if (!first) + argumentError(0, "expecting a record type"); + TypePtr t; + if (!staticToType(first, t)) + argumentError(0, "expecting a record type"); + if (t->typeKind != RECORD_TYPE) + argumentError(0, "expecting a record type"); + RecordType *rt = (RecordType *)t.ptr(); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + const vector fieldNames = recordFieldNames(rt); + if (i >= fieldNames.size()) + argumentIndexRangeError(1, "record field index", i, + fieldNames.size()); + return new MultiPValue(staticPValue(fieldNames[i].ptr())); + } - case PRIM_Tuple: - error("no Tuple type constructor overload found"); + case PRIM_RecordWithFieldP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_recordFieldRef: { + ensureArity(args, 2); + RecordTypePtr t = recordTypeOfValue(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + if (i >= t->fieldCount()) + argumentIndexRangeError(1, "record field index", i, + t->fieldCount()); + + MultiPValuePtr mpv = new MultiPValue(); + if (t->hasVarField && i >= t->varFieldPosition) + if (i == t->varFieldPosition) + for (size_t j = 0; j < t->varFieldSize(); ++j) + mpv->add(PVData(fieldTypes[i + j], false)); + else + mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); + else + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_TupleElementCount: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_recordFieldRefByName: { + ensureArity(args, 2); + RecordTypePtr t = recordTypeOfValue(args, 0); + ObjectPtr obj = unwrapStaticType(args->values[1].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(1, "expecting field name identifier"); + IdentifierPtr fname = (Identifier *)obj.ptr(); + const llvm::StringMap &fieldIndexMap = recordFieldIndexMap(t); + llvm::StringMap::const_iterator fi = + fieldIndexMap.find(fname->str); + if (fi == fieldIndexMap.end()) { + string buf; + llvm::raw_string_ostream sout(buf); + sout << "field not found: " << fname->str; + argumentError(1, sout.str()); + } + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + size_t i = fi->second; + if (t->hasVarField && i >= t->varFieldPosition) + if (i == t->varFieldPosition) + for (size_t j = 0; j < t->varFieldSize(); ++j) + mpv->add(PVData(fieldTypes[i + j], false)); + else + mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); + else + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_tupleRef: { - ensureArity(args, 2); - TupleTypePtr t = tupleTypeOfValue(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - if (i >= t->elementTypes.size()) - argumentIndexRangeError(1, "tuple element index", - i, t->elementTypes.size()); - return new MultiPValue(PVData(t->elementTypes[i], false)); - } + case PRIM_recordFields: { + ensureArity(args, 1); + RecordTypePtr t = recordTypeOfValue(args, 0); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < fieldTypes.size(); ++i) + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_tupleElements: { - ensureArity(args, 1); - TupleTypePtr t = tupleTypeOfValue(args, 0); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < t->elementTypes.size(); ++i) - mpv->add(PVData(t->elementTypes[i], false)); - return mpv; - } + case PRIM_recordVariadicField: { + ensureArity(args, 1); + RecordTypePtr t = recordTypeOfValue(args, 0); + if (!t->hasVarField) + argumentError(0, "expecting a record with a variadic field"); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + size_t varEnd = t->varFieldPosition + t->varFieldSize(); + for (size_t i = t->varFieldPosition; i < varEnd; ++i) + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_Union: - error("no Union type constructor overload found"); - - case PRIM_UnionMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_RecordP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_RecordFieldCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_RecordFieldName: { - ensureArity(args, 2); - ObjectPtr first = unwrapStaticType(args->values[0].type); - if (!first) - argumentError(0, "expecting a record type"); - TypePtr t; - if (!staticToType(first, t)) - argumentError(0, "expecting a record type"); - if (t->typeKind != RECORD_TYPE) - argumentError(0, "expecting a record type"); - RecordType *rt = (RecordType *) t.ptr(); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - const vector fieldNames = recordFieldNames(rt); - if (i >= fieldNames.size()) - argumentIndexRangeError(1, "record field index", - i, fieldNames.size()); - return new MultiPValue(staticPValue(fieldNames[i].ptr())); - } + case PRIM_VariantP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_RecordWithFieldP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_recordFieldRef: { - ensureArity(args, 2); - RecordTypePtr t = recordTypeOfValue(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - if (i >= t->fieldCount()) - argumentIndexRangeError(1, "record field index", - i, t->fieldCount()); - - MultiPValuePtr mpv = new MultiPValue(); - if (t->hasVarField && i >= t->varFieldPosition) - if (i == t->varFieldPosition) - for (size_t j = 0; j < t->varFieldSize(); ++j) - mpv->add(PVData(fieldTypes[i + j], false)); - else - mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); - else - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMemberIndex: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_recordFieldRefByName: { - ensureArity(args, 2); - RecordTypePtr t = recordTypeOfValue(args, 0); - ObjectPtr obj = unwrapStaticType(args->values[1].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(1, "expecting field name identifier"); - IdentifierPtr fname = (Identifier *) obj.ptr(); - const llvm::StringMap &fieldIndexMap = recordFieldIndexMap(t); - llvm::StringMap::const_iterator fi = - fieldIndexMap.find(fname->str); - if (fi == fieldIndexMap.end()) { - string buf; - llvm::raw_string_ostream sout(buf); - sout << "field not found: " << fname->str; - argumentError(1, sout.str()); - } - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - size_t i = fi->second; - if (t->hasVarField && i >= t->varFieldPosition) - if (i == t->varFieldPosition) - for (size_t j = 0; j < t->varFieldSize(); ++j) - mpv->add(PVData(fieldTypes[i + j], false)); - else - mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); - else - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_recordFields: { - ensureArity(args, 1); - RecordTypePtr t = recordTypeOfValue(args, 0); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < fieldTypes.size(); ++i) - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMembers: { + ensureArity(args, 1); + ObjectPtr typeObj = unwrapStaticType(args->values[0].type); + if (!typeObj) + argumentError(0, "expecting a variant type"); + TypePtr t; + if (!staticToType(typeObj, t)) + argumentError(0, "expecting a variant type"); + if (t->typeKind != VARIANT_TYPE) + argumentError(0, "expecting a variant type"); + VariantType *vt = (VariantType *)t.ptr(); + llvm::ArrayRef members = variantMemberTypes(vt); + + MultiPValuePtr mpv = new MultiPValue(); + for (TypePtr const *i = members.begin(), *end = members.end(); i != end; + ++i) { + mpv->add(staticPValue(i->ptr())); + } + return mpv; + } - case PRIM_recordVariadicField: { - ensureArity(args, 1); - RecordTypePtr t = recordTypeOfValue(args, 0); - if (!t->hasVarField) - argumentError(0, "expecting a record with a variadic field"); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - size_t varEnd = t->varFieldPosition + t->varFieldSize(); - for (size_t i = t->varFieldPosition; i < varEnd; ++i) - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_BaseType: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj && obj->objKind != TYPE) + argumentError(0, "static type expected"); + Type *type = (Type *)obj.ptr(); + MultiPValuePtr mpv = new MultiPValue(); + if (type->typeKind == NEW_TYPE) { + NewType *nt = (NewType *)type; + mpv->add(staticPValue(newtypeReprType(nt).ptr())); + } else { + mpv->add(staticPValue(type)); + } + return mpv; + } - case PRIM_VariantP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_VariantMemberIndex: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_VariantMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_VariantMembers: { - ensureArity(args, 1); - ObjectPtr typeObj = unwrapStaticType(args->values[0].type); - if (!typeObj) - argumentError(0, "expecting a variant type"); - TypePtr t; - if (!staticToType(typeObj, t)) - argumentError(0, "expecting a variant type"); - if (t->typeKind != VARIANT_TYPE) - argumentError(0, "expecting a variant type"); - VariantType *vt = (VariantType *) t.ptr(); - llvm::ArrayRef members = variantMemberTypes(vt); - - MultiPValuePtr mpv = new MultiPValue(); - for (TypePtr const *i = members.begin(), *end = members.end(); - i != end; - ++i) { - mpv->add(staticPValue(i->ptr())); - } - return mpv; - } + case PRIM_Static: + error("no Static type constructor overload found"); + + case PRIM_staticIntegers: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != VALUE_HOLDER)) + argumentError(0, "expecting a static SizeT or Int value"); + MultiPValuePtr mpv = new MultiPValue(); + ValueHolder *vh = (ValueHolder *)obj.ptr(); + if (vh->type == cIntType) { + int count = *((int *)vh->buf); + if (count < 0) + argumentError(0, "negative values are not allowed"); + for (int i = 0; i < count; ++i) { + ValueHolderPtr vhi = intToValueHolder(i); + mpv->add(PVData(staticType(vhi.ptr()), true)); + } + } else if (vh->type == cSizeTType) { + size_t count = *((size_t *)vh->buf); + for (size_t i = 0; i < count; ++i) { + ValueHolderPtr vhi = sizeTToValueHolder(i); + mpv->add(PVData(staticType(vhi.ptr()), true)); + } + } else { + argumentError(0, "expecting a static SizeT or Int value"); + } + return mpv; + } - case PRIM_BaseType: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj && obj->objKind != TYPE) - argumentError(0, "static type expected"); - Type *type = (Type *) obj.ptr(); - MultiPValuePtr mpv = new MultiPValue(); - if (type->typeKind == NEW_TYPE) { - NewType *nt = (NewType *) type; - mpv->add(staticPValue(newtypeReprType(nt).ptr())); - } else { - mpv->add(staticPValue(type)); - } - return mpv; - } + case PRIM_integers: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != VALUE_HOLDER)) + argumentError(0, "expecting a static SizeT or Int value"); + MultiPValuePtr mpv = new MultiPValue(); + ValueHolder *vh = (ValueHolder *)obj.ptr(); + if (vh->type == cIntType) { + int count = *((int *)vh->buf); + if (count < 0) + argumentError(0, "negative values are not allowed"); + for (int i = 0; i < count; ++i) + mpv->add(PVData(cIntType, true)); + } else if (vh->type == cSizeTType) { + size_t count = *((size_t *)vh->buf); + for (size_t i = 0; i < count; ++i) + mpv->add(PVData(cSizeTType, true)); + } else { + argumentError(0, "expecting a static SizeT or Int value"); + } + return mpv; + } - case PRIM_Static: - error("no Static type constructor overload found"); - - case PRIM_staticIntegers: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != VALUE_HOLDER)) - argumentError(0, "expecting a static SizeT or Int value"); - MultiPValuePtr mpv = new MultiPValue(); - ValueHolder *vh = (ValueHolder *) obj.ptr(); - if (vh->type == cIntType) { - int count = *((int *) vh->buf); - if (count < 0) - argumentError(0, "negative values are not allowed"); - for (int i = 0; i < count; ++i) { - ValueHolderPtr vhi = intToValueHolder(i); - mpv->add(PVData(staticType(vhi.ptr()), true)); - } - } else if (vh->type == cSizeTType) { - size_t count = *((size_t *) vh->buf); - for (size_t i = 0; i < count; ++i) { - ValueHolderPtr vhi = sizeTToValueHolder(i); - mpv->add(PVData(staticType(vhi.ptr()), true)); - } - } else { - argumentError(0, "expecting a static SizeT or Int value"); - } - return mpv; - } + case PRIM_staticFieldRef: { + ensureArity(args, 2); + ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); + if (!moduleObj || (moduleObj->objKind != MODULE)) + argumentError(0, "expecting a module"); + ObjectPtr identObj = unwrapStaticType(args->values[1].type); + if (!identObj || (identObj->objKind != IDENTIFIER)) + argumentError(1, "expecting a string literal value"); + Module *module = (Module *)moduleObj.ptr(); + Identifier *ident = (Identifier *)identObj.ptr(); + ObjectPtr obj = safeLookupPublic(module, ident); + return analyzeStaticObject(obj); + } - case PRIM_integers: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != VALUE_HOLDER)) - argumentError(0, "expecting a static SizeT or Int value"); - MultiPValuePtr mpv = new MultiPValue(); - ValueHolder *vh = (ValueHolder *) obj.ptr(); - if (vh->type == cIntType) { - int count = *((int *) vh->buf); - if (count < 0) - argumentError(0, "negative values are not allowed"); - for (int i = 0; i < count; ++i) - mpv->add(PVData(cIntType, true)); - } else if (vh->type == cSizeTType) { - size_t count = *((size_t *) vh->buf); - for (size_t i = 0; i < count; ++i) - mpv->add(PVData(cSizeTType, true)); - } else { - argumentError(0, "expecting a static SizeT or Int value"); - } - return mpv; - } + case PRIM_EnumP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_staticFieldRef: { - ensureArity(args, 2); - ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); - if (!moduleObj || (moduleObj->objKind != MODULE)) - argumentError(0, "expecting a module"); - ObjectPtr identObj = unwrapStaticType(args->values[1].type); - if (!identObj || (identObj->objKind != IDENTIFIER)) - argumentError(1, "expecting a string literal value"); - Module *module = (Module *) moduleObj.ptr(); - Identifier *ident = (Identifier *) identObj.ptr(); - ObjectPtr obj = safeLookupPublic(module, ident); - return analyzeStaticObject(obj); - } + case PRIM_EnumMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_EnumP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_EnumMemberName: { + ensureArity(args, 2); + EnumTypePtr et = valueToEnumType(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - case PRIM_EnumMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); + EnumDeclPtr e = et->enumeration; + if (i >= e->members.size()) + argumentIndexRangeError(1, "enum member index", i, + e->members.size()); - case PRIM_EnumMemberName: { - ensureArity(args, 2); - EnumTypePtr et = valueToEnumType(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + return analyzeStaticObject(e->members[i]->name.ptr()); + } - EnumDeclPtr e = et->enumeration; - if (i >= e->members.size()) - argumentIndexRangeError(1, "enum member index", - i, e->members.size()); + case PRIM_enumToInt: + return new MultiPValue(PVData(cIntType, true)); - return analyzeStaticObject(e->members[i]->name.ptr()); - } + case PRIM_intToEnum: { + ensureArity(args, 2); + EnumTypePtr t = valueToEnumType(args, 0); + initializeEnumType(t); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_enumToInt: - return new MultiPValue(PVData(cIntType, true)); + case PRIM_StringLiteralP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_stringLiteralByteIndex: + return new MultiPValue(PVData(cIntType, true)); + + case PRIM_stringLiteralBytes: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(0, "expecting a string literal value"); + Identifier *ident = (Identifier *)obj.ptr(); + MultiPValuePtr result = new MultiPValue(); + for (size_t i = 0, sz = ident->str.size(); i < sz; ++i) + result->add(PVData(cIntType, true)); + return result; + } - case PRIM_intToEnum: { - ensureArity(args, 2); - EnumTypePtr t = valueToEnumType(args, 0); - initializeEnumType(t); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_stringLiteralByteSize: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_stringLiteralByteSlice: { + ensureArity(args, 3); + ObjectPtr identObj = unwrapStaticType(args->values[0].type); + if (!identObj || (identObj->objKind != IDENTIFIER)) + argumentError(0, "expecting a string literal value"); + Identifier *ident = (Identifier *)identObj.ptr(); + ObjectPtr beginObj = unwrapStaticType(args->values[1].type); + ObjectPtr endObj = unwrapStaticType(args->values[2].type); + size_t begin = staticToSizeTOrIntValue(args.ptr(), 1); + size_t end = staticToSizeTOrIntValue(args.ptr(), 2); + if (end > ident->str.size()) { + argumentIndexRangeError(2, "ending index", end, ident->str.size()); + } + if (begin > end) + argumentIndexRangeError(1, "starting index", begin, end); + llvm::StringRef result(&ident->str[unsigned(begin)], end - begin); + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_StringLiteralP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_stringLiteralByteIndex: - return new MultiPValue(PVData(cIntType, true)); - - case PRIM_stringLiteralBytes: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(0, "expecting a string literal value"); - Identifier *ident = (Identifier *) obj.ptr(); - MultiPValuePtr result = new MultiPValue(); - for (size_t i = 0, sz = ident->str.size(); i < sz; ++i) - result->add(PVData(cIntType, true)); - return result; - } + case PRIM_stringLiteralConcat: { + llvm::SmallString<32> result; + for (size_t i = 0, sz = args->size(); i < sz; ++i) { + ObjectPtr obj = unwrapStaticType(args->values[unsigned(i)].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(i, "expecting a string literal value"); + Identifier *ident = (Identifier *)obj.ptr(); + result.append(ident->str.begin(), ident->str.end()); + } + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_stringLiteralByteSize: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_stringLiteralByteSlice: { - ensureArity(args, 3); - ObjectPtr identObj = unwrapStaticType(args->values[0].type); - if (!identObj || (identObj->objKind != IDENTIFIER)) - argumentError(0, "expecting a string literal value"); - Identifier *ident = (Identifier *) identObj.ptr(); - ObjectPtr beginObj = unwrapStaticType(args->values[1].type); - ObjectPtr endObj = unwrapStaticType(args->values[2].type); - size_t begin = staticToSizeTOrIntValue(args.ptr(), 1); - size_t end = staticToSizeTOrIntValue(args.ptr(), 2); - if (end > ident->str.size()) { - argumentIndexRangeError(2, "ending index", - end, ident->str.size()); - } - if (begin > end) - argumentIndexRangeError(1, "starting index", - begin, end); - llvm::StringRef result(&ident->str[unsigned(begin)], end - begin); - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_stringLiteralFromBytes: { + std::string result; + for (size_t i = 0, sz = args->size(); i < sz; ++i) { + size_t byte = staticToSizeTOrIntValue(args.ptr(), i); + if (byte > 255) { + string buf; + llvm::raw_string_ostream os(buf); + os << byte << " is too large for a string literal byte"; + argumentError(i, os.str()); + } + result.push_back((char)byte); + } + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_stringLiteralConcat: { - llvm::SmallString<32> result; - for (size_t i = 0, sz = args->size(); i < sz; ++i) { - ObjectPtr obj = unwrapStaticType(args->values[unsigned(i)].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(i, "expecting a string literal value"); - Identifier *ident = (Identifier *) obj.ptr(); - result.append(ident->str.begin(), ident->str.end()); - } - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_stringTableConstant: + return new MultiPValue(PVData(pointerType(cSizeTType), true)); - case PRIM_stringLiteralFromBytes: { - std::string result; - for (size_t i = 0, sz = args->size(); i < sz; ++i) { - size_t byte = staticToSizeTOrIntValue(args.ptr(), i); - if (byte > 255) { - string buf; - llvm::raw_string_ostream os(buf); - os << byte << " is too large for a string literal byte"; - argumentError(i, os.str()); - } - result.push_back((char) byte); - } - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_StaticName: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + llvm::SmallString<128> buf; + llvm::raw_svector_ostream sout(buf); + printStaticName(sout, obj); + return analyzeStaticObject(Identifier::get(sout.str())); + } - case PRIM_stringTableConstant: - return new MultiPValue(PVData(pointerType(cSizeTType), true)); - - case PRIM_StaticName: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - llvm::SmallString<128> buf; - llvm::raw_svector_ostream sout(buf); - printStaticName(sout, obj); - return analyzeStaticObject(Identifier::get(sout.str())); - } + case PRIM_MainModule: { + ensureArity(args, 0); + assert(globalMainModule != nullptr); + return analyzeStaticObject(globalMainModule.ptr()); + } - case PRIM_MainModule: { - ensureArity(args, 0); - assert(globalMainModule != nullptr); - return analyzeStaticObject(globalMainModule.ptr()); - } + case PRIM_StaticModule: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + ModulePtr m = staticModule(obj); + if (!m) + argumentError(0, "value has no associated module"); + return analyzeStaticObject(m.ptr()); + } - case PRIM_StaticModule: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - ModulePtr m = staticModule(obj); - if (!m) - argumentError(0, "value has no associated module"); - return analyzeStaticObject(m.ptr()); - } + case PRIM_ModuleName: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + ModulePtr m = staticModule(obj); + if (!m) + argumentError(0, "value has no associated module"); + return analyzeStaticObject(Identifier::get(m->moduleName)); + } - case PRIM_ModuleName: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - ModulePtr m = staticModule(obj); - if (!m) - argumentError(0, "value has no associated module"); - return analyzeStaticObject(Identifier::get(m->moduleName)); - } + case PRIM_ModuleMemberNames: { + ensureArity(args, 1); + ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); + if (!moduleObj || (moduleObj->objKind != MODULE)) + argumentError(0, "expecting a module"); + ModulePtr m = staticModule(moduleObj); + assert(m != nullptr); + + MultiPValuePtr result = new MultiPValue(); + + for (llvm::StringMap::const_iterator + i = m->publicGlobals.begin(), + end = m->publicGlobals.end(); + i != end; ++i) { + result->add(staticPValue(Identifier::get(i->getKey()))); + } + return result; + } - case PRIM_ModuleMemberNames: { - ensureArity(args, 1); - ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); - if (!moduleObj || (moduleObj->objKind != MODULE)) - argumentError(0, "expecting a module"); - ModulePtr m = staticModule(moduleObj); - assert(m != nullptr); - - MultiPValuePtr result = new MultiPValue(); - - for (llvm::StringMap::const_iterator i = m->publicGlobals.begin(), - end = m->publicGlobals.end(); - i != end; - ++i) { - result->add(staticPValue(Identifier::get(i->getKey()))); - } - return result; - } + case PRIM_FlagP: { + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_FlagP: { - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_Flag: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (obj != nullptr && obj->objKind == IDENTIFIER) { + Identifier *ident = (Identifier *)obj.ptr(); + + llvm::StringMap::const_iterator flag = + globalFlags.find(ident->str); + string value; + if (flag != globalFlags.end()) + value = flag->second; + + return analyzeStaticObject(Identifier::get(value)); + } else + argumentTypeError(0, "identifier", args->values[0].type); + return nullptr; + } - case PRIM_Flag: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (obj != nullptr && obj->objKind == IDENTIFIER) { - Identifier *ident = (Identifier *) obj.ptr(); - - llvm::StringMap::const_iterator flag = globalFlags.find(ident->str); - string value; - if (flag != globalFlags.end()) - value = flag->second; - - return analyzeStaticObject(Identifier::get(value)); - } else - argumentTypeError(0, "identifier", args->values[0].type); - return nullptr; - } + case PRIM_atomicFence: { + ensureArity(args, 1); + return new MultiPValue(); + } - case PRIM_atomicFence: { - ensureArity(args, 1); - return new MultiPValue(); - } + case PRIM_atomicRMW: { + // order op ptr val + ensureArity(args, 4); + pointerTypeOfValue(args, 2); + return new MultiPValue(PVData(args->values[3].type, true)); + } - case PRIM_atomicRMW: { - // order op ptr val - ensureArity(args, 4); - pointerTypeOfValue(args, 2); - return new MultiPValue(PVData(args->values[3].type, true)); - } + case PRIM_atomicLoad: { + // order ptr + ensureArity(args, 2); + PointerTypePtr pt = pointerTypeOfValue(args, 1); + return new MultiPValue(PVData(pt->pointeeType, true)); + } - case PRIM_atomicLoad: { - // order ptr - ensureArity(args, 2); - PointerTypePtr pt = pointerTypeOfValue(args, 1); - return new MultiPValue(PVData(pt->pointeeType, true)); - } + case PRIM_atomicStore: { + // order ptr val + ensureArity(args, 3); + pointerTypeOfValue(args, 1); + return new MultiPValue(); + } - case PRIM_atomicStore: { - // order ptr val - ensureArity(args, 3); - pointerTypeOfValue(args, 1); - return new MultiPValue(); - } + case PRIM_atomicCompareExchange: { + // order ptr old new + ensureArity(args, 4); + PointerTypePtr pt = pointerTypeOfValue(args, 1); - case PRIM_atomicCompareExchange: { - // order ptr old new - ensureArity(args, 4); - PointerTypePtr pt = pointerTypeOfValue(args, 1); + return new MultiPValue(PVData(args->values[2].type, true)); + } - return new MultiPValue(PVData(args->values[2].type, true)); - } + case PRIM_activeException: { + ensureArity(args, 0); + return new MultiPValue(PVData(pointerType(uint8Type), true)); + } - case PRIM_activeException: { - ensureArity(args, 0); - return new MultiPValue(PVData(pointerType(uint8Type), true)); - } + case PRIM_memcpy: + case PRIM_memmove: { + ensureArity(args, 3); + PointerTypePtr toPt = pointerTypeOfValue(args, 0); + PointerTypePtr fromPt = pointerTypeOfValue(args, 1); + integerTypeOfValue(args, 2); + return new MultiPValue(); + } - case PRIM_memcpy: - case PRIM_memmove: { - ensureArity(args, 3); - PointerTypePtr toPt = pointerTypeOfValue(args, 0); - PointerTypePtr fromPt = pointerTypeOfValue(args, 1); - integerTypeOfValue(args, 2); - return new MultiPValue(); - } + case PRIM_countValues: { + return new MultiPValue(PVData(cIntType, true)); + } - case PRIM_countValues: { - return new MultiPValue(PVData(cIntType, true)); - } + case PRIM_nthValue: { + if (args->size() < 1) + arityError2(1, args->size()); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + argumentError(0, "nthValue argument out of bounds"); + return new MultiPValue(args->values[unsigned(i) + 1]); + } - case PRIM_nthValue: { - if (args->size() < 1) - arityError2(1, args->size()); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - argumentError(0, "nthValue argument out of bounds"); - return new MultiPValue(args->values[unsigned(i) + 1]); - } + case PRIM_withoutNthValue: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + argumentError(0, "withoutNthValue argument out of bounds"); + MultiPValuePtr mpv = new MultiPValue(); + for (unsigned n = 1; n < args->size(); ++n) { + if (n == i + 1) + continue; + mpv->add(args->values[n]); + } + return mpv; + } - case PRIM_withoutNthValue: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - argumentError(0, "withoutNthValue argument out of bounds"); - MultiPValuePtr mpv = new MultiPValue(); - for (unsigned n = 1; n < args->size(); ++n) { - if (n == i + 1) - continue; - mpv->add(args->values[n]); - } - return mpv; - } + case PRIM_takeValues: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + i = args->size() - 1; + MultiPValuePtr mpv = new MultiPValue(); + for (unsigned n = 1; n < i + 1; ++n) + mpv->add(args->values[n]); + return mpv; + } - case PRIM_takeValues: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - i = args->size() - 1; - MultiPValuePtr mpv = new MultiPValue(); - for (unsigned n = 1; n < i + 1; ++n) - mpv->add(args->values[n]); - return mpv; - } + case PRIM_dropValues: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + i = args->size() - 1; + MultiPValuePtr mpv = new MultiPValue(); + for (size_t n = i + 1; n < args->size(); ++n) + mpv->add(args->values[unsigned(n)]); + return mpv; + } - case PRIM_dropValues: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - i = args->size() - 1; - MultiPValuePtr mpv = new MultiPValue(); - for (size_t n = i + 1; n < args->size(); ++n) - mpv->add(args->values[unsigned(n)]); - return mpv; - } + case PRIM_LambdaRecordP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaRecordP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaSymbolP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaSymbolP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaMonoP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaMonoP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaMonoInputTypes: { + ensureArity(args, 1); + ObjectPtr callable = unwrapStaticType(args->values[0].type); + if (!callable) + argumentError(0, "lambda record type expected"); + + if (callable != nullptr && callable->objKind == TYPE) { + Type *t = (Type *)callable.ptr(); + if (t->typeKind == RECORD_TYPE) { + RecordType *r = (RecordType *)t; + if (r->record->lambda->mono.monoState != Procedure_MonoOverload) + argumentError(0, "not a monomorphic lambda record type"); + llvm::ArrayRef monoTypes = + r->record->lambda->mono.monoTypes; + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < monoTypes.size(); ++i) + values->add(staticPValue(monoTypes[i].ptr())); - case PRIM_LambdaMonoInputTypes: { - ensureArity(args, 1); - ObjectPtr callable = unwrapStaticType(args->values[0].type); - if (!callable) - argumentError(0, "lambda record type expected"); - - if (callable != nullptr && callable->objKind == TYPE) { - Type *t = (Type *) callable.ptr(); - if (t->typeKind == RECORD_TYPE) { - RecordType *r = (RecordType *) t; - if (r->record->lambda->mono.monoState != Procedure_MonoOverload) - argumentError(0, "not a monomorphic lambda record type"); - llvm::ArrayRef monoTypes = r->record->lambda->mono.monoTypes; - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < monoTypes.size(); ++i) - values->add(staticPValue(monoTypes[i].ptr())); - - return values; - } - } - - argumentError(0, "not a monomorphic lambda record type"); - return new MultiPValue(); + return values; } + } - case PRIM_GetOverload: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - - llvm::SmallString<128> buf; - llvm::raw_svector_ostream nameout(buf); - nameout << "GetOverload("; - printStaticName(nameout, entry.second->callable); - nameout << ", "; - nameout << ")"; - - ProcedurePtr proc = new Procedure( - nullptr, Identifier::get(nameout.str()), - PRIVATE, false); - - proc->env = entry.second->env; - - CodePtr code = new Code(), origCode = entry.second->origCode; - for (vector::const_iterator arg = origCode->formalArgs.begin(), - end = origCode->formalArgs.end(); - arg != end; - ++arg) { - code->formalArgs.push_back(new FormalArg((*arg)->name, nullptr)); - } - - code->hasVarArg = origCode->hasVarArg; - - if (origCode->hasNamedReturns()) { - code->returnSpecsDeclared = true; - code->returnSpecs = origCode->returnSpecs; - code->varReturnSpec = origCode->varReturnSpec; - } - - code->body = origCode->body; - code->llvmBody = origCode->llvmBody; - - OverloadPtr overload = new Overload( - nullptr, - new ObjectExpr(proc.ptr()), - code, - entry.second->callByName, - entry.second->isInline); - overload->env = entry.second->env; - addProcedureOverload(proc, entry.second->env, overload); - - return new MultiPValue(staticPValue(proc.ptr())); - } + argumentError(0, "not a monomorphic lambda record type"); + return new MultiPValue(); + } - case PRIM_usuallyEquals: { - ensureArity(args, 2); - if (!isPrimitiveType(args->values[0].type)) - argumentTypeError(0, "primitive type", args->values[0].type); - ObjectPtr expectedValue = unwrapStaticType(args->values[1].type); - if (expectedValue == nullptr - || expectedValue->objKind != VALUE_HOLDER - || ((ValueHolder *) expectedValue.ptr())->type != args->values[0].type) - error( - "second argument to usuallyEquals must be a static value of the same type as the first argument"); - return new MultiPValue(PVData(args->values[0].type, true)); - } + case PRIM_GetOverload: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); - default: - assert(false); - return nullptr; + llvm::SmallString<128> buf; + llvm::raw_svector_ostream nameout(buf); + nameout << "GetOverload("; + printStaticName(nameout, entry.second->callable); + nameout << ", "; + nameout << ")"; + + ProcedurePtr proc = new Procedure( + nullptr, Identifier::get(nameout.str()), PRIVATE, false); + + proc->env = entry.second->env; + + CodePtr code = new Code(), origCode = entry.second->origCode; + for (vector::const_iterator + arg = origCode->formalArgs.begin(), + end = origCode->formalArgs.end(); + arg != end; ++arg) { + code->formalArgs.push_back(new FormalArg((*arg)->name, nullptr)); } + + code->hasVarArg = origCode->hasVarArg; + + if (origCode->hasNamedReturns()) { + code->returnSpecsDeclared = true; + code->returnSpecs = origCode->returnSpecs; + code->varReturnSpec = origCode->varReturnSpec; + } + + code->body = origCode->body; + code->llvmBody = origCode->llvmBody; + + OverloadPtr overload = + new Overload(nullptr, new ObjectExpr(proc.ptr()), code, + entry.second->callByName, entry.second->isInline); + overload->env = entry.second->env; + addProcedureOverload(proc, entry.second->env, overload); + + return new MultiPValue(staticPValue(proc.ptr())); + } + + case PRIM_usuallyEquals: { + ensureArity(args, 2); + if (!isPrimitiveType(args->values[0].type)) + argumentTypeError(0, "primitive type", args->values[0].type); + ObjectPtr expectedValue = unwrapStaticType(args->values[1].type); + if (expectedValue == nullptr || + expectedValue->objKind != VALUE_HOLDER || + ((ValueHolder *)expectedValue.ptr())->type != args->values[0].type) + error("second argument to usuallyEquals must be a static value of " + "the same type as the first argument"); + return new MultiPValue(PVData(args->values[0].type, true)); + } + + default: + assert(false); + return nullptr; } } +} // namespace clay diff --git a/compiler/analyzer_op.hpp b/compiler/analyzer_op.hpp index af8a2c32..60bdf3e4 100644 --- a/compiler/analyzer_op.hpp +++ b/compiler/analyzer_op.hpp @@ -3,5 +3,5 @@ #include "clay.hpp" namespace clay { - MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args); +MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args); } diff --git a/compiler/checkedcast.hpp b/compiler/checkedcast.hpp index a38b06b5..be7e9917 100644 --- a/compiler/checkedcast.hpp +++ b/compiler/checkedcast.hpp @@ -3,10 +3,9 @@ #include "assert.h" namespace clay { - template - To checked_cast(From *from) { - // TODO: for unknown reason this code cause SEGV in runtime - //assert(!from || dynamic_cast(from)); - return static_cast(from); - } +template To checked_cast(From *from) { + // TODO: for unknown reason this code cause SEGV in runtime + // assert(!from || dynamic_cast(from)); + return static_cast(from); } +} // namespace clay diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 6a034da0..94fb8a26 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,16 +1,25 @@ +#include +#include +#include +#include +#include + #include "clay.hpp" -#include "hirestimer.hpp" -#include "error.hpp" #include "codegen.hpp" -#include "loader.hpp" +#include "error.hpp" +#include "hirestimer.hpp" #include "invoketables.hpp" +#include "loader.hpp" #include "parachute.hpp" +using std::string; +using std::vector; + // for _exit #ifdef _WIN32 -# include +#include #else -# include +#include #endif namespace clay { @@ -26,1161 +35,1090 @@ namespace clay { #define ENV_SEPARATOR ':' #endif - using namespace std; - - static void addOptimizationPasses(llvm::legacy::PassManager &passes, - llvm::legacy::FunctionPassManager &fpasses, - unsigned optLevel, - bool internalize) { - llvm::Pass *inliningPass = 0; - if (optLevel > 1) { - int threshold = 225; - if (optLevel > 2) - threshold = 275; - inliningPass = llvm::createFunctionInliningPass(threshold); - } else { - inliningPass = llvm::createAlwaysInlinerPass(); - } - - llvm::PassManagerBuilder builder; - builder.OptLevel = optLevel; - builder.Inliner = inliningPass; - - builder.populateFunctionPassManager(fpasses); - - // If all optimizations are disabled, just run the always-inline pass. - if (optLevel == 0) { - if (builder.Inliner) { - passes.add(builder.Inliner); - builder.Inliner = 0; - } - } else { - passes.add(llvm::createTypeBasedAliasAnalysisPass()); - passes.add(llvm::createBasicAliasAnalysisPass()); +static bool runModule(llvm::Module *module, + const std::vector &argv, + char const *const *envp, + llvm::ArrayRef libSearchPaths, + llvm::ArrayRef libs) { + auto JIT_expected = llvm::orc::LLJITBuilder().create(); + if (!JIT_expected) { + llvm::errs() << "error creating JIT: " + << llvm::toString(JIT_expected.takeError()) << "\n"; + return false; + } + auto JIT = std::move(JIT_expected.get()); + llvm::orc::LLJIT &jit = *JIT; - passes.add(llvm::createGlobalOptimizerPass()); // Optimize out global vars + llvm::orc::JITDylib &mainDylib = jit.getMainJITDylib(); - passes.add(llvm::createIPSCCPPass()); // IP SCCP - passes.add(llvm::createDeadArgEliminationPass()); // Dead argument elimination + auto Generator_expected = + llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + jit.getDataLayout().getGlobalPrefix()); - passes.add(llvm::createInstructionCombiningPass()); // Clean up after IPCP & DAE - passes.add(llvm::createCFGSimplificationPass()); // Clean up after IPCP & DAE + if (!Generator_expected) { + llvm::errs() << "error creating generator: " + << llvm::toString(Generator_expected.takeError()) << "\n"; + return false; + } - // Start of CallGraph SCC passes. - if (builder.Inliner) { - passes.add(builder.Inliner); - builder.Inliner = 0; - } - if (optLevel > 2) - passes.add(llvm::createArgumentPromotionPass()); // Scalarize uninlined fn args - - // Start of function pass. - // Break up aggregate allocas, using SSAUpdater. - passes.add(llvm::createScalarReplAggregatesPass(-1, false)); - passes.add(llvm::createEarlyCSEPass()); // Catch trivial redundancies - - passes.add(llvm::createJumpThreadingPass()); // Thread jumps. - // Disable Value Propagation pass until fixed LLVM bug #12503 - // passes.add(llvm::createCorrelatedValuePropagationPass()); // Propagate conditionals - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createInstructionCombiningPass()); // Combine silly seq's - - passes.add(llvm::createTailCallEliminationPass()); // Eliminate tail calls - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createReassociatePass()); // Reassociate expressions - passes.add(llvm::createLoopRotatePass()); // Rotate Loop - passes.add(llvm::createLICMPass()); // Hoist loop invariants - passes.add(llvm::createLoopUnswitchPass(builder.SizeLevel || optLevel < 3)); - passes.add(llvm::createInstructionCombiningPass()); - passes.add(llvm::createIndVarSimplifyPass()); // Canonicalize indvars - passes.add(llvm::createLoopIdiomPass()); // Recognize idioms like memset. - passes.add(llvm::createLoopDeletionPass()); // Delete dead loops - - if (optLevel > 1) - passes.add(llvm::createGVNPass()); // Remove redundancies - passes.add(llvm::createMemCpyOptPass()); // Remove memcpy / form memset - passes.add(llvm::createSCCPPass()); // Constant prop with SCCP - - // Run instcombine after redundancy elimination to exploit opportunities - // opened up by them. - passes.add(llvm::createInstructionCombiningPass()); - passes.add(llvm::createJumpThreadingPass()); // Thread jumps - // Disable Value Propagation pass until fixed LLVM bug #12503 - // passes.add(llvm::createCorrelatedValuePropagationPass()); - passes.add(llvm::createDeadStoreEliminationPass()); // Delete dead stores - - if (builder.Vectorize) { - passes.add(llvm::createBBVectorizePass()); - passes.add(llvm::createInstructionCombiningPass()); - if (optLevel > 1) - passes.add(llvm::createGVNPass()); // Remove redundancies - } + std::unique_ptr Generator = + std::move(*Generator_expected); - passes.add(llvm::createAggressiveDCEPass()); // Delete dead instructions - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createInstructionCombiningPass()); // Clean up after everything. + mainDylib.addGenerator(std::move(Generator)); - // GlobalOpt already deletes dead functions and globals, at -O3 try a - // late pass of GlobalDCE. It is capable of deleting dead cycles. - if (optLevel > 2) - passes.add(llvm::createGlobalDCEPass()); // Remove dead fns and globals. + module->setDataLayout(jit.getDataLayout()); - if (optLevel > 1) - passes.add(llvm::createConstantMergePass()); // Merge dup global constants - } + auto TSM = + llvm::orc::ThreadSafeModule(std::unique_ptr(module), + std::make_unique()); - if (optLevel > 2) { - if (internalize) { - vector do_not_internalize; - do_not_internalize.push_back("main"); - passes.add(llvm::createInternalizePass(do_not_internalize)); - } - builder.populateLTOPassManager(passes, false, true); - } + if (llvm::Error AddIRErr = jit.addIRModule(std::move(TSM))) { + llvm::errs() << "error adding module to JIT: " + << llvm::toString(std::move(AddIRErr)) << "\n"; + return false; } - static bool linkLibraries(llvm::Module *module, llvm::ArrayRef libSearchPaths, - llvm::ArrayRef libs) { - if (libs.empty()) - return true; - llvm::Linker linker("clay", llvmModule, llvm::Linker::Verbose); - linker.addSystemPaths(); - linker.addPaths(libSearchPaths); - for (size_t i = 0; i < libs.size(); ++i) { - string lib = libs[i]; - llvmModule->addLibrary(lib); - //as in cling/lib/Interpreter/Interpreter.cpp - bool isNative = true; - if (linker.LinkInLibrary(lib, isNative)) { - // that didn't work, try bitcode: - llvm::sys::Path FilePath(lib); - std::string Magic; - if (!FilePath.getMagicNumber(Magic, 64)) { - // filename doesn't exist... - linker.releaseModule(); - return false; - } - if (llvm::sys::IdentifyFileType(Magic.c_str(), 64) - == llvm::sys::Bitcode_FileType) { - // We are promised a bitcode file, complain if it fails - linker.setFlags(0); - if (linker.LinkInFile(llvm::sys::Path(lib), isNative)) { - linker.releaseModule(); - return false; - } - } else { - // Nothing the linker can handle - linker.releaseModule(); - return false; - } - } else if (isNative) { - // native shared library, load it! - llvm::sys::Path SoFile = linker.FindLib(lib); - if (SoFile.isEmpty()) { - llvm::errs() << "Couldn't find shared library " << lib << "\n"; - linker.releaseModule(); - return false; - } - std::string errMsg; - bool hasError = llvm::sys::DynamicLibrary - ::LoadLibraryPermanently(SoFile.str().c_str(), &errMsg); - if (hasError) { - if (hasError) { - llvm::errs() << "Couldn't load shared library " << lib << "\n" << errMsg.c_str(); - linker.releaseModule(); - return false; - } - } - } - } - linker.releaseModule(); - return true; + auto mainAddr_expected = jit.lookup("main"); + if (!mainAddr_expected) { + llvm::errs() << "error resolving main: " + << llvm::toString(mainAddr_expected.takeError()) << "\n"; + return false; } - static bool runModule(llvm::Module *module, - vector &argv, - char const *const*envp, - llvm::ArrayRef libSearchPaths, - llvm::ArrayRef libs) { - if (!linkLibraries(module, libSearchPaths, libs)) { - return false; - } - llvm::EngineBuilder eb(llvmModule); - llvm::ExecutionEngine *engine = eb.create(); - llvm::Function *mainFunc = module->getFunction("main"); - if (!mainFunc) { - llvm::errs() << "no main function to -run\n"; - delete engine; - return false; - } - engine->runStaticConstructorsDestructors(false); - engine->runFunctionAsMain(mainFunc, argv, envp); - engine->runStaticConstructorsDestructors(true); + using MainPtr = int (*)(int, char *[], char *[]); - delete engine; - return true; + llvm::orc::ExecutorAddr mainAddr = mainAddr_expected.get(); + auto mainFunc = reinterpret_cast(mainAddr.getValue()); + + std::vector c_argv; + for (const auto &arg : argv) { + c_argv.push_back(arg.c_str()); } + c_argv.push_back(nullptr); - static void optimizeLLVM(llvm::Module *module, unsigned optLevel, bool internalize) { - llvm::PassManager passes; + mainFunc(static_cast(c_argv.size() - 1), + const_cast(c_argv.data()), const_cast(envp)); - string moduleDataLayout = module->getDataLayout(); - llvm::DataLayout *dl = new llvm::DataLayout(moduleDataLayout); - passes.add(dl); + return true; +} - llvm::FunctionPassManager fpasses(module); +static void optimizeLLVM(llvm::Module *module, unsigned optLevel, + bool internalize) { + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + llvm::PassBuilder PB; + + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::OptimizationLevel O = llvm::OptimizationLevel::O0; + if (optLevel == 1) + O = llvm::OptimizationLevel::O1; + else if (optLevel == 2) + O = llvm::OptimizationLevel::O2; + else if (optLevel >= 3) + O = llvm::OptimizationLevel::O3; + + llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(O); + + if (optLevel > 2 && internalize) { + MPM.addPass(llvm::InternalizePass([=](const llvm::GlobalValue &GV) { + return GV.getName() == "main"; + })); + } - fpasses.add(new llvm::DataLayout(*dl)); + MPM.addPass(llvm::VerifierPass()); - addOptimizationPasses(passes, fpasses, optLevel, internalize); + MPM.run(*module, MAM); +} - fpasses.doInitialization(); - for (llvm::Module::iterator i = module->begin(), e = module->end(); - i != e; ++i) { - fpasses.run(*i); - } +static void generateLLVM(llvm::Module *module, bool emitAsm, + llvm::raw_ostream *out) { + llvm::ModuleAnalysisManager MAM; + llvm::ModulePassManager passes; - passes.add(llvm::createVerifierPass()); - passes.run(*module); - } + if (emitAsm) + passes.addPass(llvm::PrintModulePass(*out)); + else + passes.addPass(llvm::BitcodeWriterPass(*out)); - static void generateLLVM(llvm::Module *module, bool emitAsm, llvm::raw_ostream *out) { - llvm::PassManager passes; - if (emitAsm) - passes.add(llvm::createPrintModulePass(out)); - else - passes.add(llvm::createBitcodeWriterPass(*out)); - passes.run(*module); - } + passes.run(*module, MAM); +} - static void generateAssembly(llvm::Module *module, - llvm::TargetMachine *targetMachine, - llvm::raw_ostream *out, - bool emitObject) { - llvm::FunctionPassManager fpasses(module); +static void generateAssembly(llvm::Module *module, + llvm::TargetMachine *targetMachine, + llvm::raw_pwrite_stream *out, bool emitObject) { + llvm::legacy::PassManager passes; - fpasses.add(new llvm::DataLayout(module)); - fpasses.add(llvm::createVerifierPass()); + passes.add(llvm::createVerifierPass()); - targetMachine->setAsmVerbosityDefault(true); + llvm::CodeGenFileType fileType = emitObject + ? llvm::CodeGenFileType::ObjectFile + : llvm::CodeGenFileType::AssemblyFile; - llvm::formatted_raw_ostream fout(*out); - llvm::TargetMachine::CodeGenFileType fileType = emitObject - ? llvm::TargetMachine::CGFT_ObjectFile - : llvm::TargetMachine::CGFT_AssemblyFile; + if (targetMachine->addPassesToEmitFile(passes, *out, nullptr, fileType)) { + llvm::errs() << "error: adding codegen passes failed\n"; + return; + } - bool result = targetMachine->addPassesToEmitFile(fpasses, fout, fileType); - assert(!result); + passes.run(*module); +} - fpasses.doInitialization(); - for (llvm::Module::iterator i = module->begin(), e = module->end(); - i != e; ++i) { - fpasses.run(*i); +[[maybe_unused]] static std::string +joinCmdArgs(llvm::ArrayRef args) { + std::string s; + llvm::raw_string_ostream ss(s); + for (const llvm::StringRef &arg : args) { + if (&arg != args.begin()) { + ss << " "; } - fpasses.doFinalization(); + ss << arg; } + return s; +} - static string joinCmdArgs(llvm::ArrayRef args) { - string s; - llvm::raw_string_ostream ss(s); - for (char const *const *arg = args.begin(); - arg != args.end(); ++arg) { - if (arg != args.begin()) { - ss << " "; - } - if (*arg == 0 && arg + 1 == args.end()) { - continue; - } - ss << *arg; - } - return s; +static bool generateBinary(llvm::Module *module, + llvm::TargetMachine *targetMachine, + llvm::Twine const &outputFilePath, + llvm::StringRef const &clangPath, + bool /*exceptions*/, bool sharedLib, bool debug, + llvm::ArrayRef arguments, bool verbose) { + int fd; + PathString tempObj; + if (std::error_code ec = llvm::sys::fs::createUniqueFile( + "clayobj-%%%%%%%%.obj", fd, tempObj)) { + llvm::errs() << "error creating temporary object file: " << ec.message() + << '\n'; + return false; } + llvm::FileRemover removeTempObj(tempObj); - static bool generateBinary(llvm::Module *module, - llvm::TargetMachine *targetMachine, - llvm::Twine const &outputFilePath, - llvm::sys::Path const &clangPath, - bool /*exceptions*/, - bool sharedLib, - bool debug, - llvm::ArrayRef arguments, - bool verbose) { - int fd; - PathString tempObj; - if (llvm::error_code ec = llvm::sys::fs::unique_file("clayobj-%%%%%%%%.obj", fd, tempObj)) { - llvm::errs() << "error creating temporary object file: " << ec.message() << '\n'; - return false; - } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(tempObj)); - - { - llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/ true); + { + llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/true); - generateAssembly(module, targetMachine, &objOut, true); - } + generateAssembly(module, targetMachine, &objOut, true); + } - string outputFilePathStr = outputFilePath.str(); + string outputFilePathStr = outputFilePath.str(); - vector clangArgs; - clangArgs.push_back(clangPath.c_str()); + std::vector clangArgs; + clangArgs.emplace_back(clangPath.data()); - switch (llvmDataLayout->getPointerSizeInBits()) { - case 32: - clangArgs.push_back("-m32"); - break; - case 64: - clangArgs.push_back("-m64"); - break; - default: - assert(false); - } + switch (llvmDataLayout->getPointerSizeInBits()) { + case 32: + clangArgs.emplace_back("-m32"); + break; + case 64: + clangArgs.emplace_back("-m64"); + break; + default: + assert(false); + } - llvm::Triple triple(llvmModule->getTargetTriple()); - string linkerFlags; - if (sharedLib) { - clangArgs.push_back("-shared"); + llvm::Triple triple(llvmModule->getTargetTriple()); + if (sharedLib) { + clangArgs.emplace_back("-shared"); - if (triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { - PathString defPath; - outputFilePath.toVector(defPath); - llvm::sys::path::replace_extension(defPath, "def"); + if (triple.isOSWindows()) { + string linkerFlags; + PathString defPath; + outputFilePath.toVector(defPath); + llvm::sys::path::replace_extension(defPath, "def"); - linkerFlags = "-Wl,--output-def," + string(defPath.begin(), defPath.end()); + linkerFlags = + "-Wl,--output-def," + string(defPath.begin(), defPath.end()); - clangArgs.push_back(linkerFlags.c_str()); - } - } - if (debug) { - if (triple.getOS() == llvm::Triple::Win32) - clangArgs.push_back("-Wl,/debug"); - } - clangArgs.push_back("-o"); - clangArgs.push_back(outputFilePathStr.c_str()); - clangArgs.push_back(tempObj.c_str()); - for (unsigned i = 0; i < arguments.size(); ++i) - clangArgs.push_back(arguments[i].c_str()); - clangArgs.push_back(nullptr); - - if (verbose) { - llvm::errs() << "executing clang to generate binary:\n"; - llvm::errs() << " " << joinCmdArgs(clangArgs) << "\n"; + clangArgs.emplace_back(linkerFlags); } + } + if (debug) { + if (triple.getOS() == llvm::Triple::Win32) + clangArgs.emplace_back("-Wl,/debug"); + } + clangArgs.emplace_back("-o"); + clangArgs.emplace_back(outputFilePathStr); + clangArgs.push_back(tempObj); + for (const auto &argument : arguments) + clangArgs.emplace_back(argument); + + if (verbose) { + llvm::errs() << "executing clang to generate binary:\n"; + llvm::errs() << " " << joinCmdArgs(clangArgs) << "\n"; + } - int result = llvm::sys::Program::ExecuteAndWait(clangPath, &clangArgs[0]); + int result = llvm::sys::ExecuteAndWait(clangPath, clangArgs); - if (debug && triple.getOS() == llvm::Triple::Darwin) { - llvm::sys::Path dsymutilPath = llvm::sys::Program::FindProgramByName("dsymutil"); - if (dsymutilPath.isValid()) { - string outputDSYMPath = outputFilePathStr; - outputDSYMPath.append(".dSYM"); + if (debug && triple.isOSDarwin()) { + llvm::ErrorOr dsymutilPathOrErr = + llvm::sys::findProgramByName("dsymutil"); + if (std::error_code ec = dsymutilPathOrErr.getError()) + llvm::errs() << "error creating dsymutil: " << ec.message() << '\n'; - vector dsymutilArgs; - dsymutilArgs.push_back(dsymutilPath.c_str()); - dsymutilArgs.push_back("-o"); - dsymutilArgs.push_back(outputDSYMPath.c_str()); - dsymutilArgs.push_back(outputFilePathStr.c_str()); - dsymutilArgs.push_back(nullptr); + std::string dsymutilPath = dsymutilPathOrErr ? *dsymutilPathOrErr : ""; - if (verbose) { - llvm::errs() << "executing dsymutil:"; - llvm::errs() << " " << joinCmdArgs(dsymutilArgs) << "\n"; - } + if (!dsymutilPath.empty()) { + string outputDSYMPath = outputFilePathStr; + outputDSYMPath.append(".dSYM"); - int dsymResult = llvm::sys::Program::ExecuteAndWait(dsymutilPath, - &dsymutilArgs[0]); + std::vector dsymutilArgs; + dsymutilArgs.emplace_back(dsymutilPath); + dsymutilArgs.emplace_back("-o"); + dsymutilArgs.emplace_back(outputDSYMPath); + dsymutilArgs.emplace_back(outputFilePathStr); - if (dsymResult != 0) - llvm::errs() << "warning: dsymutil exited with error code " << dsymResult << "\n"; - } else - llvm::errs() << - "warning: unable to find dsymutil on the path; debug info for executable will not be generated\n"; - } + if (verbose) { + llvm::errs() << "executing dsymutil:"; + llvm::errs() << " " << joinCmdArgs(dsymutilArgs) << "\n"; + } - bool dontcare; - llvm::sys::fs::remove(llvm::StringRef(tempObj), dontcare); + int dsymResult = + llvm::sys::ExecuteAndWait(dsymutilPath, dsymutilArgs); - return (result == 0); + if (dsymResult != 0) + llvm::errs() << "warning: dsymutil exited with error code " + << dsymResult << "\n"; + } else + llvm::errs() << "warning: unable to find dsymutil on the path; " + "debug info for executable will not be generated\n"; } - static void usage(char *argv0) { - llvm::errs() << "usage: " << argv0 << " \n"; - llvm::errs() << " " << argv0 << " -e \n"; - llvm::errs() << "options:\n"; - llvm::errs() << " -o specify output file\n"; - llvm::errs() << " -target set target platform for code generation\n"; - llvm::errs() << " -mcpu set target CPU for code generation\n"; - llvm::errs() << " -mattr set target features for code generation\n" - << " use +feature to enable a feature\n" - << " or -feature to disable it\n" - << " for example, -mattr +feature1,-feature2\n"; - llvm::errs() << " -soft-float generate software floating point library calls\n"; - llvm::errs() << " -shared create a dynamically linkable library\n"; - llvm::errs() << " -emit-llvm emit llvm code\n"; - llvm::errs() << " -S emit assembler code\n"; - llvm::errs() << " -c emit object code\n"; - llvm::errs() << " -DFLAG[=value] set flag value\n" - << " (queryable with Flag?() and Flag())\n"; - llvm::errs() << " -O0 -O1 -O2 -O3 set optimization level\n"; - llvm::errs() << " (default -O2, or -O0 with -g)\n"; - llvm::errs() << " -g keep debug symbol information\n"; - llvm::errs() << " -exceptions enable exception handling\n"; - llvm::errs() << " -no-exceptions disable exception handling\n"; - llvm::errs() << " -inline inline procedures marked 'forceinline'\n"; - llvm::errs() << " and enable 'inline' hints (default)\n"; - llvm::errs() << " -no-inline ignore 'inline' and 'forceinline' keyword\n"; - llvm::errs() << " -import-externals include externals from imported modules\n" - << " in compilation unit\n" - << " (default when building standalone or -shared)\n"; - llvm::errs() << " -no-import-externals don't include externals from imported modules\n" - << " in compilation unit\n" - << " (default when building -c or -S)\n"; - llvm::errs() << " -pic generate position independent code\n"; - llvm::errs() << " -run execute the program without writing to disk\n"; - llvm::errs() << " -timing show timing information\n"; - llvm::errs() << " -verbose be verbose\n"; - llvm::errs() << " -full-match-errors show universal patterns in match failure errors\n"; - llvm::errs() << " -log-match \n" - << " log overload matching behavior for calls to \n" - << " in module \n"; + return (result == 0); +} + +static void usage(const char *argv0) { + llvm::errs() << "usage: " << argv0 << " \n"; + llvm::errs() << " " << argv0 << " -e \n"; + llvm::errs() << "options:\n"; + llvm::errs() << " -o specify output file\n"; + llvm::errs() + << " -target set target platform for code generation\n"; + llvm::errs() + << " -mcpu set target CPU for code generation\n"; + llvm::errs() + << " -mattr set target features for code generation\n" + << " use +feature to enable a feature\n" + << " or -feature to disable it\n" + << " for example, -mattr +feature1,-feature2\n"; + llvm::errs() << " -soft-float generate software floating point " + "library calls\n"; + llvm::errs() + << " -shared create a dynamically linkable library\n"; + llvm::errs() << " -emit-llvm emit llvm code\n"; + llvm::errs() << " -S emit assembler code\n"; + llvm::errs() << " -c emit object code\n"; + llvm::errs() + << " -DFLAG[=value] set flag value\n" + << " (queryable with Flag?() and Flag())\n"; + llvm::errs() << " -O0 -O1 -O2 -O3 set optimization level\n"; + llvm::errs() << " (default -O2, or -O0 with -g)\n"; + llvm::errs() << " -g keep debug symbol information\n"; + llvm::errs() << " -exceptions enable exception handling\n"; + llvm::errs() << " -no-exceptions disable exception handling\n"; + llvm::errs() + << " -inline inline procedures marked 'forceinline'\n"; + llvm::errs() + << " and enable 'inline' hints (default)\n"; + llvm::errs() << " -no-inline ignore 'inline' and 'forceinline' " + "keyword\n"; + llvm::errs() + << " -import-externals include externals from imported modules\n" + << " in compilation unit\n" + << " (default when building standalone or " + "-shared)\n"; + llvm::errs() + << " -no-import-externals don't include externals from imported " + "modules\n" + << " in compilation unit\n" + << " (default when building -c or -S)\n"; + llvm::errs() + << " -pic generate position independent code\n"; + llvm::errs() << " -run execute the program without " + "writing to disk\n"; + llvm::errs() << " -timing show timing information\n"; + llvm::errs() << " -verbose be verbose\n"; + llvm::errs() << " -full-match-errors show universal patterns in match " + "failure errors\n"; + llvm::errs() << " -log-match \n" + << " log overload matching behavior " + "for calls to \n" + << " in module \n"; #ifdef __APPLE__ - llvm::errs() << " -arch build for Darwin architecture \n"; - llvm::errs() << " -F add to framework search path\n"; - llvm::errs() << " -framework link with framework \n"; + llvm::errs() + << " -arch build for Darwin architecture \n"; + llvm::errs() + << " -F add to framework search path\n"; + llvm::errs() << " -framework link with framework \n"; #endif - llvm::errs() << " -L add to library search path\n"; - llvm::errs() << " -Wl, pass flags to linker\n"; - llvm::errs() << " -l link with library \n"; - llvm::errs() << " -I add to clay module search path\n"; - llvm::errs() << " -deps keep track of the dependencies of the currently\n"; - llvm::errs() << " compiling file and write them to the file\n"; - llvm::errs() << " specified by -o-deps\n"; - llvm::errs() << " -no-deps don't generate dependencies file\n"; - llvm::errs() << " -o-deps write the dependencies to this file\n"; - llvm::errs() << " (defaults to .d)\n"; - llvm::errs() << " -e compile and run (implies -run)\n"; - llvm::errs() << " -M \"import .*;\" for -e\n"; - llvm::errs() << " -version display version info\n"; - - llvm::errs() << " -final-overloads enable final overloads (temporary option)\n"; - } + llvm::errs() + << " -L add to library search path\n"; + llvm::errs() << " -Wl, pass flags to linker\n"; + llvm::errs() << " -l link with library \n"; + llvm::errs() + << " -I add to clay module search path\n"; + llvm::errs() << " -deps keep track of the dependencies of " + "the currently\n"; + llvm::errs() << " compiling file and write them to " + "the file\n"; + llvm::errs() << " specified by -o-deps\n"; + llvm::errs() + << " -no-deps don't generate dependencies file\n"; + llvm::errs() + << " -o-deps write the dependencies to this file\n"; + llvm::errs() << " (defaults to .d)\n"; + llvm::errs() + << " -e compile and run (implies -run)\n"; + llvm::errs() << " -M \"import .*;\" for -e\n"; + llvm::errs() << " -version display version info\n"; + + llvm::errs() << " -final-overloads enable final overloads (temporary " + "option)\n"; +} - static string sharedExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32 - || triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { - return ".dll"; - } else if (triple.getOS() == llvm::Triple::Darwin) { - return ".dylib"; - } else { - return ".so"; - } +static string sharedExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".dll"; } + if (triple.isOSDarwin()) { + return ".dylib"; + } + return ".so"; +} - static string objExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32) { - return ".obj"; - } else { - return ".o"; - } +static string objExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".obj"; } + return ".o"; +} - static string exeExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32 - || triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { - return ".exe"; - } else { - return ""; - } +static string exeExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".exe"; } + return ""; +} - static void printVersion() { - llvm::errs() << "clay compiler version " CLAY_COMPILER_VERSION - ", language version " CLAY_LANGUAGE_VERSION " (" +static void printVersion() { + llvm::errs() << "clay compiler version " CLAY_COMPILER_VERSION + ", language version " CLAY_LANGUAGE_VERSION " (" #ifdef GIT_ID - << "git id " << GIT_ID << ", " + << "git id " << GIT_ID << ", " #endif #ifdef HG_ID - << "hg id " << HG_ID << ", " + << "hg id " << HG_ID << ", " #endif #ifdef SVN_REVISION - << "llvm r" << SVN_REVISION << ", " + << "llvm r" << SVN_REVISION << ", " #endif - << __DATE__ << ")\n"; - } + << __DATE__ << ")\n"; +} - int main2(int argc, char **argv, char const *const*envp) { - if (argc == 1) { - usage(argv[0]); - return 2; - } +int main2(int argc, char **argv, char const *const *envp) { + if (argc == 1) { + usage(argv[0]); + return 2; + } - bool emitLLVM = false; - bool emitAsm = false; - bool emitObject = false; - bool sharedLib = false; - bool genPIC = false; - bool inlineEnabled = true; - bool exceptions = true; - bool run = false; - bool repl = false; - bool verbose = false; - bool crossCompiling = false; - bool showTiming = false; - bool codegenExternals = false; - bool codegenExternalsSet = false; - - bool generateDeps = false; - - unsigned optLevel = 2; - bool optLevelSet = false; - - bool finalOverloadsEnabled = false; - bool softFloat = false; + bool emitLLVM = false; + bool emitAsm = false; + bool emitObject = false; + bool sharedLib = false; + bool genPIC = false; + bool inlineEnabled = true; + bool exceptions = true; + bool run = false; + bool repl = false; + bool verbose = false; + bool crossCompiling = false; + bool showTiming = false; + bool codegenExternals = false; + bool codegenExternalsSet = false; + + bool generateDeps = false; + + unsigned optLevel = 2; + bool optLevelSet = false; + + bool finalOverloadsEnabled = false; + bool softFloat = false; #ifdef __APPLE__ - genPIC = true; + genPIC = true; - string arch; + string arch; #endif - string clayFile; - string outputFile; - string targetTriple = llvm::sys::getDefaultTargetTriple(); + string clayFile; + string outputFile; + string targetTriple = llvm::sys::getDefaultTargetTriple(); - string targetCPU; - string targetFeatures; + string targetCPU; + string targetFeatures; - string clayScriptImports; - string clayScript; + string clayScriptImports; + string clayScript; - vector libSearchPathArgs; - vector libSearchPath; - string linkerFlags; - vector librariesArgs; - vector libraries; - vector searchPath; + vector libSearchPathArgs; + vector libSearchPath; + string linkerFlags; + vector librariesArgs; + vector libraries; + vector searchPath; - string dependenciesOutputFile; + string dependenciesOutputFile; #ifdef __APPLE__ - vector frameworkSearchPath; - vector frameworks; + vector frameworkSearchPath; + vector frameworks; #endif - bool debug = false; - - for (int i = 1; i < argc; ++i) { - if ((strcmp(argv[i], "-shared") == 0)) { - sharedLib = true; - } else if (strcmp(argv[i], "-emit-llvm") == 0) { - emitLLVM = true; - } else if (strcmp(argv[i], "-S") == 0) { - emitAsm = true; - } else if (strcmp(argv[i], "-c") == 0) { - emitObject = true; - } else if (strcmp(argv[i], "-g") == 0) { - debug = true; - if (!optLevelSet) - optLevel = 0; - } else if (strcmp(argv[i], "-O0") == 0) { + bool debug = false; + + for (int i = 1; i < argc; ++i) { + if ((strcmp(argv[i], "-shared") == 0)) { + sharedLib = true; + } else if (strcmp(argv[i], "-emit-llvm") == 0) { + emitLLVM = true; + } else if (strcmp(argv[i], "-S") == 0) { + emitAsm = true; + } else if (strcmp(argv[i], "-c") == 0) { + emitObject = true; + } else if (strcmp(argv[i], "-g") == 0) { + debug = true; + if (!optLevelSet) optLevel = 0; - optLevelSet = true; - } else if (strcmp(argv[i], "-O1") == 0) { - optLevel = 1; - optLevelSet = true; - } else if (strcmp(argv[i], "-O2") == 0) { - optLevel = 2; - optLevelSet = true; - } else if (strcmp(argv[i], "-O3") == 0) { - optLevel = 3; - optLevelSet = true; - } else if (strcmp(argv[i], "-inline") == 0) { - inlineEnabled = true; - } else if (strcmp(argv[i], "-no-inline") == 0) { - inlineEnabled = false; - } else if (strcmp(argv[i], "-exceptions") == 0) { - exceptions = true; - } else if (strcmp(argv[i], "-no-exceptions") == 0) { - exceptions = false; - } else if (strcmp(argv[i], "-pic") == 0) { - genPIC = true; - } else if (strcmp(argv[i], "-verbose") == 0 || strcmp(argv[i], "-v") == 0) { - verbose = true; - } else if (strcmp(argv[i], "-run") == 0) { - run = true; - } else if (strcmp(argv[i], "-repl") == 0) { - repl = true; - } else if (strcmp(argv[i], "-timing") == 0) { - showTiming = true; - } else if (strcmp(argv[i], "-full-match-errors") == 0) { - shouldPrintFullMatchErrors = true; - } else if (strcmp(argv[i], "-log-match") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: symbol name missing after -log-match\n"; - return 1; - } - ++i; - char const *dot = strrchr(argv[i], '.'); - if (dot == nullptr) { - logMatchSymbols.insert(make_pair(string("*"), argv[i])); - } else { - logMatchSymbols.insert(make_pair(string((char const *) argv[i], dot), string(dot + 1))); - } - } else if (strcmp(argv[i], "-e") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: source string missing after -e\n"; - return 1; - } - ++i; - run = true; - clayScript += argv[i]; - clayScript += "\n"; - } else if (strncmp(argv[i], "-M", 2) == 0) { - string modulespec = argv[i] + 2; - if (modulespec.empty()) { - llvm::errs() << "error: module missing after -M\n"; - return 1; - } - clayScriptImports += "import " + modulespec + ".*; "; - } else if (strcmp(argv[i], "-o") == 0) { - ++i; - if (i == argc) { - llvm::errs() << "error: filename missing after -o\n"; - return 1; - } - if (!outputFile.empty()) { - llvm::errs() << "error: output file already specified: " - << outputFile - << ", specified again as " << argv[i] << '\n'; - return 1; - } - outputFile = argv[i]; + } else if (strcmp(argv[i], "-O0") == 0) { + optLevel = 0; + optLevelSet = true; + } else if (strcmp(argv[i], "-O1") == 0) { + optLevel = 1; + optLevelSet = true; + } else if (strcmp(argv[i], "-O2") == 0) { + optLevel = 2; + optLevelSet = true; + } else if (strcmp(argv[i], "-O3") == 0) { + optLevel = 3; + optLevelSet = true; + } else if (strcmp(argv[i], "-inline") == 0) { + inlineEnabled = true; + } else if (strcmp(argv[i], "-no-inline") == 0) { + inlineEnabled = false; + } else if (strcmp(argv[i], "-exceptions") == 0) { + exceptions = true; + } else if (strcmp(argv[i], "-no-exceptions") == 0) { + exceptions = false; + } else if (strcmp(argv[i], "-pic") == 0) { + genPIC = true; + } else if (strcmp(argv[i], "-verbose") == 0 || + strcmp(argv[i], "-v") == 0) { + verbose = true; + } else if (strcmp(argv[i], "-run") == 0) { + run = true; + } else if (strcmp(argv[i], "-repl") == 0) { + repl = true; + } else if (strcmp(argv[i], "-timing") == 0) { + showTiming = true; + } else if (strcmp(argv[i], "-full-match-errors") == 0) { + shouldPrintFullMatchErrors = true; + } else if (strcmp(argv[i], "-log-match") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: symbol name missing after -log-match\n"; + return 1; + } + ++i; + char const *dot = strrchr(argv[i], '.'); + if (dot == nullptr) { + logMatchSymbols.insert(make_pair(string("*"), argv[i])); + } else { + logMatchSymbols.insert( + make_pair(string(static_cast(argv[i]), dot), + string(dot + 1))); + } + } else if (strcmp(argv[i], "-e") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: source string missing after -e\n"; + return 1; + } + ++i; + run = true; + clayScript += argv[i]; + clayScript += "\n"; + } else if (strncmp(argv[i], "-M", 2) == 0) { + string modulespec = argv[i] + 2; + if (modulespec.empty()) { + llvm::errs() << "error: module missing after -M\n"; + return 1; + } + clayScriptImports += "import " + modulespec + ".*; "; + } else if (strcmp(argv[i], "-o") == 0) { + ++i; + if (i == argc) { + llvm::errs() << "error: filename missing after -o\n"; + return 1; + } + if (!outputFile.empty()) { + llvm::errs() + << "error: output file already specified: " << outputFile + << ", specified again as " << argv[i] << '\n'; + return 1; } + outputFile = argv[i]; + } #ifdef __APPLE__ - else if (strstr(argv[i], "-F") == argv[i]) { - string frameworkDir = argv[i] + strlen("-F"); - if (frameworkDir.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: directory missing after -F\n"; - return 1; - } - ++i; - frameworkDir = argv[i]; - if (frameworkDir.empty() || (frameworkDir[0] == '-')) { - llvm::errs() << "error: directory missing after -F\n"; - return 1; - } - } - frameworkSearchPath.push_back("-F" + frameworkDir); - } else if (strcmp(argv[i], "-framework") == 0) { + else if (strstr(argv[i], "-F") == argv[i]) { + string frameworkDir = argv[i] + strlen("-F"); + if (frameworkDir.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: framework name missing after -framework\n"; + llvm::errs() << "error: directory missing after -F\n"; return 1; } ++i; - string framework = argv[i]; - if (framework.empty() || (framework[0] == '-')) { - llvm::errs() << "error: framework name missing after -framework\n"; - return 1; - } - frameworks.push_back("-framework"); - frameworks.push_back(framework); - } else if (strcmp(argv[i], "-arch") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: architecture name missing after -arch\n"; - return 1; - } - ++i; - if (!arch.empty()) { - llvm::errs() << "error: multiple -arch flags currently unsupported\n"; - return 1; - } - arch = argv[i]; - if (arch.empty() || (arch[0] == '-')) { - llvm::errs() << "error: architecture name missing after -arch\n"; + frameworkDir = argv[i]; + if (frameworkDir.empty() || (frameworkDir[0] == '-')) { + llvm::errs() << "error: directory missing after -F\n"; return 1; } + } + frameworkSearchPath.push_back("-F" + frameworkDir); + } else if (strcmp(argv[i], "-framework") == 0) { + if (i + 1 == argc) { + llvm::errs() + << "error: framework name missing after -framework\n"; + return 1; + } + ++i; + string framework = argv[i]; + if (framework.empty() || (framework[0] == '-')) { + llvm::errs() + << "error: framework name missing after -framework\n"; + return 1; + } + frameworks.emplace_back("-framework"); + frameworks.push_back(framework); + } else if (strcmp(argv[i], "-arch") == 0) { + if (i + 1 == argc) { + llvm::errs() + << "error: architecture name missing after -arch\n"; + return 1; + } + ++i; + if (!arch.empty()) { + llvm::errs() + << "error: multiple -arch flags currently unsupported\n"; + return 1; + } + arch = argv[i]; + if (arch.empty() || (arch[0] == '-')) { + llvm::errs() + << "error: architecture name missing after -arch\n"; + return 1; + } - if (arch == "i386") { - targetTriple = "i386-apple-darwin10"; - } else if (arch == "x86_64") { - targetTriple = "x86_64-apple-darwin10"; - } else if (arch == "ppc") { - targetTriple = "powerpc-apple-darwin10"; - } else if (arch == "ppc64") { - targetTriple = "powerpc64-apple-darwin10"; - } else if (arch == "armv6") { - targetTriple = "armv6-apple-darwin4.1-iphoneos"; - } else if (arch == "armv7") { - targetTriple = "thumbv7-apple-darwin4.1-iphoneos"; - } else { - llvm::errs() << "error: unrecognized -arch value " << arch << "\n"; - return 1; - } + if (arch == "i386") { + targetTriple = "i386-apple-darwin10"; + } else if (arch == "x86_64") { + targetTriple = "x86_64-apple-darwin10"; + } else if (arch == "ppc") { + targetTriple = "powerpc-apple-darwin10"; + } else if (arch == "ppc64") { + targetTriple = "powerpc64-apple-darwin10"; + } else if (arch == "armv6") { + targetTriple = "armv6-apple-darwin4.1-iphoneos"; + } else if (arch == "armv7") { + targetTriple = "thumbv7-apple-darwin4.1-iphoneos"; + } else { + llvm::errs() + << "error: unrecognized -arch value " << arch << "\n"; + return 1; } + } #endif - else if (strcmp(argv[i], "-target") == 0) { + else if (strcmp(argv[i], "-target") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: target name missing after -target\n"; + return 1; + } + ++i; + targetTriple = argv[i]; + if (targetTriple.empty() || (targetTriple[0] == '-')) { + llvm::errs() << "error: target name missing after -target\n"; + return 1; + } + crossCompiling = + targetTriple != llvm::sys::getDefaultTargetTriple(); + } else if (strcmp(argv[i], "-mcpu") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: CPU name missing after -mcpu\n"; + return 1; + } + ++i; + targetCPU = argv[i]; + if (targetCPU.empty() || (targetCPU[0] == '-')) { + llvm::errs() << "error: CPU name missing after -mcpu\n"; + return 1; + } + } else if (strcmp(argv[i], "-mattr") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: features missing after -mattr\n"; + return 1; + } + ++i; + targetFeatures = argv[i]; + if (targetFeatures.empty() || (targetFeatures[0] == '-')) { + llvm::errs() << "error: features missing after -mattr\n"; + return 1; + } + } else if (strcmp(argv[i], "-soft-float") == 0) { + softFloat = true; + } else if (strstr(argv[i], "-Wl") == argv[i]) { + linkerFlags += argv[i] + strlen("-Wl"); + } else if (strstr(argv[i], "-L") == argv[i]) { + string libDir = argv[i] + strlen("-L"); + if (libDir.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: target name missing after -target\n"; + llvm::errs() << "error: directory missing after -L\n"; return 1; } ++i; - targetTriple = argv[i]; - if (targetTriple.empty() || (targetTriple[0] == '-')) { - llvm::errs() << "error: target name missing after -target\n"; + libDir = argv[i]; + if (libDir.empty() || (libDir[0] == '-')) { + llvm::errs() << "error: directory missing after -L\n"; return 1; } - crossCompiling = targetTriple != llvm::sys::getDefaultTargetTriple(); - } else if (strcmp(argv[i], "-mcpu") == 0) { + } + libSearchPath.push_back(libDir); + libSearchPathArgs.push_back("-L" + libDir); + } else if (strstr(argv[i], "-l") == argv[i]) { + string lib = argv[i] + strlen("-l"); + if (lib.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: CPU name missing after -mcpu\n"; + llvm::errs() << "error: library missing after -l\n"; return 1; } ++i; - targetCPU = argv[i]; - if (targetCPU.empty() || (targetCPU[0] == '-')) { - llvm::errs() << "error: CPU name missing after -mcpu\n"; + lib = argv[i]; + if (lib.empty() || (lib[0] == '-')) { + llvm::errs() << "error: library missing after -l\n"; return 1; } - } else if (strcmp(argv[i], "-mattr") == 0) { + } + libraries.push_back(lib); + librariesArgs.push_back("-l" + lib); + } else if (strstr(argv[i], "-D") == argv[i]) { + char *namep = argv[i] + strlen("-D"); + if (namep[0] == '\0') { if (i + 1 == argc) { - llvm::errs() << "error: features missing after -mattr\n"; + llvm::errs() << "error: definition missing after -D\n"; return 1; } ++i; - targetFeatures = argv[i]; - if (targetFeatures.empty() || (targetFeatures[0] == '-')) { - llvm::errs() << "error: features missing after -mattr\n"; - return 1; - } - } else if (strcmp(argv[i], "-soft-float") == 0) { - softFloat = true; - } else if (strstr(argv[i], "-Wl") == argv[i]) { - linkerFlags += argv[i] + strlen("-Wl"); - } else if (strstr(argv[i], "-L") == argv[i]) { - string libDir = argv[i] + strlen("-L"); - if (libDir.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: directory missing after -L\n"; - return 1; - } - ++i; - libDir = argv[i]; - if (libDir.empty() || (libDir[0] == '-')) { - llvm::errs() << "error: directory missing after -L\n"; - return 1; - } - } - libSearchPath.push_back(libDir); - libSearchPathArgs.push_back("-L" + libDir); - } else if (strstr(argv[i], "-l") == argv[i]) { - string lib = argv[i] + strlen("-l"); - if (lib.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: library missing after -l\n"; - return 1; - } - ++i; - lib = argv[i]; - if (lib.empty() || (lib[0] == '-')) { - llvm::errs() << "error: library missing after -l\n"; - return 1; - } - } - libraries.push_back(lib); - librariesArgs.push_back("-l" + lib); - } else if (strstr(argv[i], "-D") == argv[i]) { - char *namep = argv[i] + strlen("-D"); - if (namep[0] == '\0') { - if (i + 1 == argc) { - llvm::errs() << "error: definition missing after -D\n"; - return 1; - } - ++i; - namep = argv[i]; - if (namep[0] == '\0' || namep[0] == '-') { - llvm::errs() << "error: definition missing after -D\n"; - return 1; - } - } - char *equalSignp = strchr(namep, '='); - string name = equalSignp == nullptr - ? string(namep) - : string(namep, equalSignp); - string value = equalSignp == nullptr - ? string() - : string(equalSignp + 1); - - globalFlags[name] = value; - } else if (strstr(argv[i], "-I") == argv[i]) { - string path = argv[i] + strlen("-I"); - if (path.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: path missing after -I\n"; - return 1; - } - ++i; - path = argv[i]; - if (path.empty() || (path[0] == '-')) { - llvm::errs() << "error: path missing after -I\n"; - return 1; - } - } - searchPath.push_back(PathString(path)); - } else if (strstr(argv[i], "-version") == argv[i] - || strcmp(argv[i], "--version") == 0) { - printVersion(); - return 0; - } else if (strcmp(argv[i], "-import-externals") == 0) { - codegenExternals = true; - codegenExternalsSet = true; - } else if (strcmp(argv[i], "-no-import-externals") == 0) { - codegenExternals = false; - codegenExternalsSet = true; - } else if (strcmp(argv[i], "-deps") == 0) { - generateDeps = true; - } else if (strcmp(argv[i], "-no-deps") == 0) { - generateDeps = false; - } else if (strcmp(argv[i], "-o-deps") == 0) { - ++i; - if (i == argc) { - llvm::errs() << "error: filename missing after -o-deps\n"; + namep = argv[i]; + if (namep[0] == '\0' || namep[0] == '-') { + llvm::errs() << "error: definition missing after -D\n"; return 1; } - if (!dependenciesOutputFile.empty()) { - llvm::errs() << "error: dependencies output file already specified: " - << dependenciesOutputFile - << ", specified again as " << argv[i] << '\n'; + } + char *equalSignp = strchr(namep, '='); + string name = equalSignp == nullptr ? string(namep) + : string(namep, equalSignp); + string value = + equalSignp == nullptr ? string() : string(equalSignp + 1); + + globalFlags[name] = value; + } else if (strstr(argv[i], "-I") == argv[i]) { + string path = argv[i] + strlen("-I"); + if (path.empty()) { + if (i + 1 == argc) { + llvm::errs() << "error: path missing after -I\n"; return 1; } - dependenciesOutputFile = argv[i]; - } else if (strcmp(argv[i], "--") == 0) { ++i; - if (clayFile.empty()) { - if (i != argc - 1) { - llvm::errs() << "error: clay file already specified: " << argv[i] - << ", unrecognized parameter: " << argv[i + 1] << '\n'; - return 1; - } - clayFile = argv[i]; - } else { - if (i != argc) { - llvm::errs() << "error: clay file already specified: " << clayFile - << ", unrecognized parameter: " << argv[i] << '\n'; - return 1; - } - } - } else if (strcmp(argv[i], "-help") == 0 - || strcmp(argv[i], "--help") == 0 - || strcmp(argv[i], "/?") == 0) { - usage(argv[0]); - return 2; - } else if (strstr(argv[i], "-") != argv[i]) { - if (!clayFile.empty()) { - llvm::errs() << "error: clay file already specified: " << clayFile - << ", unrecognized parameter: " << argv[i] << '\n'; + path = argv[i]; + if (path.empty() || (path[0] == '-')) { + llvm::errs() << "error: path missing after -I\n"; return 1; } - clayFile = argv[i]; - } else if (strcmp(argv[i], "-final-overloads") == 0) { - finalOverloadsEnabled = true; - } else { - llvm::errs() << "error: unrecognized option " << argv[i] << '\n'; - return 1; } - } - - if (verbose) { + searchPath.emplace_back(path); + } else if (strstr(argv[i], "-version") == argv[i] || + strcmp(argv[i], "--version") == 0) { printVersion(); - } - - if (repl && clayScript.empty() && clayFile.empty()) { - clayScript = "/*empty module if file not specified*/"; - } else { - if (clayScript.empty() && clayFile.empty()) { - llvm::errs() << "error: clay file not specified\n"; + return 0; + } else if (strcmp(argv[i], "-import-externals") == 0) { + codegenExternals = true; + codegenExternalsSet = true; + } else if (strcmp(argv[i], "-no-import-externals") == 0) { + codegenExternals = false; + codegenExternalsSet = true; + } else if (strcmp(argv[i], "-deps") == 0) { + generateDeps = true; + } else if (strcmp(argv[i], "-no-deps") == 0) { + generateDeps = false; + } else if (strcmp(argv[i], "-o-deps") == 0) { + ++i; + if (i == argc) { + llvm::errs() << "error: filename missing after -o-deps\n"; return 1; } - if (!clayScript.empty() && !clayFile.empty()) { - llvm::errs() << "error: -e cannot be specified with input file\n"; + if (!dependenciesOutputFile.empty()) { + llvm::errs() + << "error: dependencies output file already specified: " + << dependenciesOutputFile << ", specified again as " + << argv[i] << '\n'; return 1; } + dependenciesOutputFile = argv[i]; + } else if (strcmp(argv[i], "--") == 0) { + ++i; + if (clayFile.empty()) { + if (i != argc - 1) { + llvm::errs() + << "error: clay file already specified: " << argv[i] + << ", unrecognized parameter: " << argv[i + 1] << '\n'; + return 1; + } + clayFile = argv[i]; + } else { + if (i != argc) { + llvm::errs() + << "error: clay file already specified: " << clayFile + << ", unrecognized parameter: " << argv[i] << '\n'; + return 1; + } + } + } else if (strcmp(argv[i], "-help") == 0 || + strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "/?") == 0) { + usage(argv[0]); + return 2; + } else if (strstr(argv[i], "-") != argv[i]) { + if (!clayFile.empty()) { + llvm::errs() + << "error: clay file already specified: " << clayFile + << ", unrecognized parameter: " << argv[i] << '\n'; + return 1; + } + clayFile = argv[i]; + } else if (strcmp(argv[i], "-final-overloads") == 0) { + finalOverloadsEnabled = true; + } else { + llvm::errs() << "error: unrecognized option " << argv[i] << '\n'; + return 1; } + } - if (!clayScriptImports.empty() && clayScript.empty()) { - llvm::errs() << "error: -M specified without -e\n"; - } + if (verbose) { + printVersion(); + } - if (emitAsm && emitObject) { - llvm::errs() << "error: -S or -c cannot be used together\n"; + if (repl && clayScript.empty() && clayFile.empty()) { + clayScript = "/*empty module if file not specified*/"; + } else { + if (clayScript.empty() && clayFile.empty()) { + llvm::errs() << "error: clay file not specified\n"; return 1; } - - if (crossCompiling && run) { - llvm::errs() << "error: cannot use -run when cross compiling\n"; + if (!clayScript.empty() && !clayFile.empty()) { + llvm::errs() << "error: -e cannot be specified with input file\n"; return 1; } + } - if (crossCompiling && !(emitLLVM || emitAsm || emitObject) + if (!clayScriptImports.empty() && clayScript.empty()) { + llvm::errs() << "error: -M specified without -e\n"; + } + + if (emitAsm && emitObject) { + llvm::errs() << "error: -S or -c cannot be used together\n"; + return 1; + } + + if (crossCompiling && run) { + llvm::errs() << "error: cannot use -run when cross compiling\n"; + return 1; + } + + if (crossCompiling && !(emitLLVM || emitAsm || emitObject) #ifdef __APPLE__ - && arch.empty() + && arch.empty() #endif - ) { - llvm::errs() << "error: must use -emit-llvm, -S, or -c when cross compiling\n"; - return 1; - } + ) { + llvm::errs() + << "error: must use -emit-llvm, -S, or -c when cross compiling\n"; + return 1; + } - if (!codegenExternalsSet) - codegenExternals = !(emitLLVM || emitAsm || emitObject); + if (!codegenExternalsSet) + codegenExternals = !(emitLLVM || emitAsm || emitObject); - if ((emitLLVM || emitAsm || emitObject) && run) - run = false; + if ((emitLLVM || emitAsm || emitObject) && run) + run = false; - setInlineEnabled(inlineEnabled); - setExceptionsEnabled(exceptions); + setInlineEnabled(inlineEnabled); + setExceptionsEnabled(exceptions); - setFinalOverloadsEnabled(finalOverloadsEnabled); + setFinalOverloadsEnabled(finalOverloadsEnabled); - llvm::Triple llvmTriple(targetTriple); - targetTriple = llvmTriple.str(); + llvm::Triple llvmTriple(targetTriple); + targetTriple = llvmTriple.str(); - std::string moduleName = clayScript.empty() ? clayFile : "-e"; + std::string moduleName = clayScript.empty() ? clayFile : "-e"; - llvm::TargetMachine *targetMachine = initLLVM(targetTriple, - targetCPU, targetFeatures, softFloat, moduleName, "", - (sharedLib || genPIC), debug, optLevel); - if (targetMachine == nullptr) { - llvm::errs() << "error: unable to initialize LLVM for target " << targetTriple << "\n"; - return 1; - } + llvm::TargetMachine *targetMachine = + initLLVM(targetTriple, targetCPU, targetFeatures, softFloat, moduleName, + "", (sharedLib || genPIC), debug, optLevel); + if (targetMachine == nullptr) { + llvm::errs() << "error: unable to initialize LLVM for target " + << targetTriple << "\n"; + return 1; + } - initTypes(); - initExternalTarget(targetTriple); - - // Try environment variables first - char *libclayPath = getenv("CLAY_PATH"); - if (libclayPath) { - // Parse the environment variable - // Format expected is standard PATH form, i.e - // CLAY_PATH=path1:path2:path3 (on unix) - // CLAY_PATH=path1;path2;path3 (on windows) - char *begin = libclayPath; - char *end; - do { - end = begin; - while (*end && (*end != ENV_SEPARATOR)) - ++end; - searchPath.push_back(llvm::StringRef(begin, (size_t) (end - begin))); - begin = end + 1; - } while (*end); - } - // Add the relative path from the executable - PathString clayExe(llvm::sys::Path::GetMainExecutable(argv[0], (void *) (uintptr_t) &usage).c_str()); - llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); + initTypes(); + initExternalTarget(targetTriple); + + // Try environment variables first + if (char *libclayPath = getenv("CLAY_PATH")) { + // Parse the environment variable + // Format expected is standard PATH form, i.e. + // CLAY_PATH=path1:path2:path3 (on Unix) + // CLAY_PATH=path1;path2;path3 (on Windows) + char *begin = libclayPath; + char *end; + do { + end = begin; + while (*end && (*end != ENV_SEPARATOR)) + ++end; + searchPath.emplace_back( + llvm::StringRef(begin, static_cast(end - begin))); + begin = end + 1; + } while (*end); + } + // Add the relative path from the executable + PathString clayExe(llvm::sys::fs::getMainExecutable( + argv[0], reinterpret_cast(&usage))); + llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); - PathString libDirDevelopment(clayDir); - PathString libDirProduction1(clayDir); - PathString libDirProduction2(clayDir); + PathString libDirDevelopment(clayDir); + PathString libDirProduction1(clayDir); + PathString libDirProduction2(clayDir); - llvm::sys::path::append(libDirDevelopment, "../../lib-clay"); - llvm::sys::path::append(libDirProduction1, "../lib/lib-clay"); - llvm::sys::path::append(libDirProduction2, "lib-clay"); + llvm::sys::path::append(libDirDevelopment, "../../lib-clay"); + llvm::sys::path::append(libDirProduction1, "../lib/lib-clay"); + llvm::sys::path::append(libDirProduction2, "lib-clay"); - searchPath.push_back(libDirDevelopment); - searchPath.push_back(libDirProduction1); - searchPath.push_back(libDirProduction2); - searchPath.push_back(PathString(".")); + searchPath.push_back(libDirDevelopment); + searchPath.push_back(libDirProduction1); + searchPath.push_back(libDirProduction2); + searchPath.emplace_back("."); - if (verbose) { - llvm::errs() << "using search path:\n"; + if (verbose) { + llvm::errs() << "using search path:\n"; - for (std::vector::const_iterator it = searchPath.begin(); - it != searchPath.end(); ++it) { - llvm::errs() << " " << *it << "\n"; - } + for (const auto &it : searchPath) { + llvm::errs() << " " << it << "\n"; } + } - setSearchPath(searchPath); - - if (outputFile.empty()) { - llvm::StringRef clayFileBasename = llvm::sys::path::stem(clayFile); - outputFile = string(clayFileBasename.begin(), clayFileBasename.end()); - - if (emitLLVM && emitAsm) - outputFile += ".ll"; - else if (emitAsm) - outputFile += ".s"; - else if (emitObject || emitLLVM) - outputFile += objExtensionForTarget(llvmTriple); - else if (sharedLib) - outputFile += sharedExtensionForTarget(llvmTriple); - else - outputFile += exeExtensionForTarget(llvmTriple); - } - if (!run) { - bool isDir; - if (!llvm::sys::fs::is_directory(outputFile, isDir) && isDir) { - llvm::errs() << "error: output file '" << outputFile << "' is a directory\n"; - return 1; - } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(outputFile)); + setSearchPath(searchPath); + + if (outputFile.empty()) { + llvm::StringRef clayFileBasename = llvm::sys::path::stem(clayFile); + outputFile = string(clayFileBasename.begin(), clayFileBasename.end()); + + if (emitLLVM && emitAsm) + outputFile += ".ll"; + else if (emitAsm) + outputFile += ".s"; + else if (emitObject || emitLLVM) + outputFile += objExtensionForTarget(llvmTriple); + else if (sharedLib) + outputFile += sharedExtensionForTarget(llvmTriple); + else + outputFile += exeExtensionForTarget(llvmTriple); + } + if (!run) { + bool isDir; + if (!llvm::sys::fs::is_directory(outputFile, isDir) && isDir) { + llvm::errs() << "error: output file '" << outputFile + << "' is a directory\n"; + return 1; } + llvm::sys::RemoveFileOnSignal(outputFile); + } - if (generateDeps) { - if (run) { - llvm::errs() << "error: '-deps' can not be used together with '-e' or '-run'\n"; - return 1; - } - if (dependenciesOutputFile.empty()) { - dependenciesOutputFile = outputFile; - dependenciesOutputFile += ".d"; - } + if (generateDeps) { + if (run) { + llvm::errs() << "error: '-deps' can not be used together with '-e' " + "or '-run'\n"; + return 1; + } + if (dependenciesOutputFile.empty()) { + dependenciesOutputFile = outputFile; + dependenciesOutputFile += ".d"; } + } - if (generateDeps) { - bool isDir; - if (!llvm::sys::fs::is_directory(dependenciesOutputFile, isDir) && isDir) { - llvm::errs() << "error: dependencies output file '" << dependenciesOutputFile << "' is a directory\n"; - return 1; - } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(dependenciesOutputFile)); + if (generateDeps) { + bool isDir; + if (!llvm::sys::fs::is_directory(dependenciesOutputFile, isDir) && + isDir) { + llvm::errs() << "error: dependencies output file '" + << dependenciesOutputFile << "' is a directory\n"; + return 1; } + llvm::sys::RemoveFileOnSignal(dependenciesOutputFile); + } - HiResTimer loadTimer, compileTimer, optTimer, outputTimer; + HiResTimer loadTimer, compileTimer, optTimer, outputTimer; - //compiler + // compiler - loadTimer.start(); - try { - initLoader(); + loadTimer.start(); + try { + initLoader(); - ModulePtr m; + ModulePtr m; + vector sourceFiles; + if (!clayScript.empty()) { string clayScriptSource; - vector sourceFiles; - if (!clayScript.empty()) { - clayScriptSource = clayScriptImports + "main() {\n" + clayScript + "}"; - m = loadProgramSource("-e", clayScriptSource, verbose, repl); - } else if (generateDeps) - m = loadProgram(clayFile, &sourceFiles, verbose, repl); - else - m = loadProgram(clayFile, nullptr, verbose, repl); - - loadTimer.stop(); - compileTimer.start(); - codegenEntryPoints(m, codegenExternals); - compileTimer.stop(); - - if (generateDeps) { - string errorInfo; - - if (verbose) { - llvm::errs() << "generating dependencies into " << dependenciesOutputFile << "\n"; - } + clayScriptSource = + clayScriptImports + "main() {\n" + clayScript + "}"; + m = loadProgramSource("-e", clayScriptSource, verbose, repl); + } else if (generateDeps) + m = loadProgram(clayFile, &sourceFiles, verbose, repl); + else + m = loadProgram(clayFile, nullptr, verbose, repl); - llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile.c_str(), - errorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!errorInfo.empty()) { - llvm::errs() << "error: " << errorInfo << '\n'; - return 1; - } - dependenciesOut << outputFile << ": \\\n"; - for (size_t i = 0; i < sourceFiles.size(); ++i) { - dependenciesOut << " " << sourceFiles[i]; - if (i < sourceFiles.size() - 1) - dependenciesOut << " \\\n"; - } + loadTimer.stop(); + compileTimer.start(); + codegenEntryPoints(m, codegenExternals); + compileTimer.stop(); + + if (generateDeps) { + std::error_code ec; + + if (verbose) { + llvm::errs() << "generating dependencies into " + << dependenciesOutputFile << "\n"; + } + + llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile, ec, + llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() + << "error creating dependencies file: " << ec.message() + << '\n'; + return 1; + } + dependenciesOut << outputFile << ": \\\n"; + for (size_t i = 0; i < sourceFiles.size(); ++i) { + dependenciesOut << " " << sourceFiles[i]; + if (i < sourceFiles.size() - 1) + dependenciesOut << " \\\n"; } + } - bool internalize = true; - if (debug || sharedLib || run || !codegenExternals) - internalize = false; + bool internalize = true; + if (debug || sharedLib || run || !codegenExternals) + internalize = false; - optTimer.start(); + optTimer.start(); - if (!repl) { - if (optLevel > 0) - optimizeLLVM(llvmModule, optLevel, internalize); + if (!repl) { + if (optLevel > 0) + optimizeLLVM(llvmModule, optLevel, internalize); + } + optTimer.stop(); + + if (run) { + vector runArgs; + runArgs.push_back(clayFile); + runModule(llvmModule, runArgs, envp, libSearchPath, libraries); + } else if (repl) { + // TODO: future me task + runInteractive(llvmModule, m); + } else if (emitLLVM || emitAsm || emitObject) { + std::error_code ec; + + llvm::raw_fd_ostream out(outputFile, ec, llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() + << "error creating output file: " << ec.message() << '\n'; + return 1; } - optTimer.stop(); - - if (run) { - vector argv; - argv.push_back(clayFile); - runModule(llvmModule, argv, envp, libSearchPath, libraries); - } else if (repl) { - linkLibraries(llvmModule, libSearchPath, libraries); - runInteractive(llvmModule, m); - } else if (emitLLVM || emitAsm || emitObject) { - string errorInfo; - llvm::raw_fd_ostream out(outputFile.c_str(), - errorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!errorInfo.empty()) { - llvm::errs() << "error: " << errorInfo << '\n'; - return 1; - } - outputTimer.start(); - if (emitLLVM) - generateLLVM(llvmModule, emitAsm, &out); - else if (emitAsm || emitObject) - generateAssembly(llvmModule, targetMachine, &out, emitObject); - outputTimer.stop(); - } else { - bool result; - llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang"); - if (!clangPath.isValid()) { - llvm::errs() << "error: unable to find clang on the path\n"; - return 1; - } + outputTimer.start(); + if (emitLLVM) + generateLLVM(llvmModule, emitAsm, &out); + else if (emitAsm || emitObject) + generateAssembly(llvmModule, targetMachine, &out, emitObject); + outputTimer.stop(); + } else { + bool result; + llvm::ErrorOr clangPathOrErr = + llvm::sys::findProgramByName("clang"); + if (std::error_code ec = clangPathOrErr.getError()) { + llvm::errs() << "error: unable to find clang on the path: " + << ec.message() << "\n"; + return 1; + } + const std::string &clangPath = clangPathOrErr.get(); - vector arguments; + vector arguments; #ifdef __APPLE__ - if (!arch.empty()) { - arguments.push_back("-arch"); - arguments.push_back(arch); - } + if (!arch.empty()) { + arguments.emplace_back("-arch"); + arguments.push_back(arch); + } #endif - if (!linkerFlags.empty()) - arguments.push_back("-Wl" + linkerFlags); + if (!linkerFlags.empty()) + arguments.push_back("-Wl" + linkerFlags); #ifdef __APPLE__ - copy( - frameworkSearchPath.begin(), - frameworkSearchPath.end(), - back_inserter(arguments) - ); - copy(frameworks.begin(), frameworks.end(), back_inserter(arguments)); + copy(frameworkSearchPath.begin(), frameworkSearchPath.end(), + back_inserter(arguments)); + copy(frameworks.begin(), frameworks.end(), + back_inserter(arguments)); #endif - copy( - libSearchPathArgs.begin(), - libSearchPathArgs.end(), - back_inserter(arguments) - ); - copy(librariesArgs.begin(), librariesArgs.end(), back_inserter(arguments)); - - outputTimer.start(); - result = generateBinary(llvmModule, targetMachine, outputFile, clangPath, - exceptions, sharedLib, debug, arguments, verbose); - outputTimer.stop(); - if (!result) - return 1; - } - } catch (const CompilerError &) { - return 1; - } - if (showTiming) { - llvm::errs() << "load time = " << (size_t) loadTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "compile time = " << (size_t) compileTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "optimization time = " << (size_t) optTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "codegen time = " << (size_t) outputTimer.elapsedMillis() << " ms\n"; - llvm::errs().flush(); + copy(libSearchPathArgs.begin(), libSearchPathArgs.end(), + back_inserter(arguments)); + copy(librariesArgs.begin(), librariesArgs.end(), + back_inserter(arguments)); + + outputTimer.start(); + result = generateBinary(llvmModule, targetMachine, outputFile, + clangPath, exceptions, sharedLib, debug, + arguments, verbose); + outputTimer.stop(); + if (!result) + return 1; } - - _exit(0); + } catch (const CompilerError &) { + return 1; + } + if (showTiming) { + llvm::errs() << "load time = " + << static_cast(loadTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "compile time = " + << static_cast(compileTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "optimization time = " + << static_cast(optTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "codegen time = " + << static_cast(outputTimer.elapsedMillis()) + << " ms\n"; + llvm::errs().flush(); } + + _exit(0); } +} // namespace clay -int main(int argc, char **argv, char const *const*envp) { +int main(int argc, char **argv, char const *const *envp) { return clay::parachute(clay::main2, argc, argv, envp); } diff --git a/compiler/clay.hpp b/compiler/clay.hpp index cd467c93..6c8147f4 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -5,56 +5,68 @@ #define _SCL_SECURE_NO_WARNINGS #endif -#include -#include +#include #include #include -#include +#include +#include #ifdef _MSC_VER // LLVM headers spew warnings on MSVC #pragma warning(push) -#pragma warning(disable: 4146 4244 4267 4355 4146 4800 4996) +#pragma warning(disable : 4146 4244 4267 4355 4146 4800 4996) #endif -#include +#include #include #include #include #include #include -#include #include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include #include -#include #include +#include #include #include -#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include #include +#include +#include #include +#include +#include +#include #include +#include #include #include #include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include +#include +#include +#include #include @@ -65,31 +77,28 @@ #include "refcounted.hpp" namespace clay { - template - struct StaticAssertChecker; - - template<> - struct StaticAssertChecker { - typedef int type; - }; - - template<> - struct StaticAssertChecker { - }; - -#define _CLAY_CAT(a,b) a##b -#define CLAY_CAT(a,b) _CLAY_CAT(a,b) - -#define CLAY_STATIC_ASSERT(cond) \ - static const ::clay::StaticAssertChecker<(cond)>::type CLAY_CAT(static_assert_, __LINE__); - - using std::string; - using std::vector; - using std::pair; - using std::make_pair; - using std::map; - using std::set; -} +template struct StaticAssertChecker; + +template <> struct StaticAssertChecker { + typedef int type; +}; + +template <> struct StaticAssertChecker {}; + +#define _CLAY_CAT(a, b) a##b +#define CLAY_CAT(a, b) _CLAY_CAT(a, b) + +#define CLAY_STATIC_ASSERT(cond) \ + static const ::clay::StaticAssertChecker<(cond)>::type CLAY_CAT( \ + static_assert_, __LINE__); + +using std::make_pair; +using std::map; +using std::pair; +using std::set; +using std::string; +using std::vector; +} // namespace clay #ifdef _MSC_VER @@ -102,34 +111,36 @@ namespace clay { #include namespace clay { - typedef std::complex clay_cfloat; - typedef std::complex clay_cdouble; - typedef std::complex clay_cldouble; +typedef std::complex clay_cfloat; +typedef std::complex clay_cdouble; +typedef std::complex clay_cldouble; - template - inline T clay_creal(std::complex const &c) { return std::real(c); } +template inline T clay_creal(std::complex const &c) { + return std::real(c); +} - template - inline T clay_cimag(std::complex const &c) { return std::imag(c); } +template inline T clay_cimag(std::complex const &c) { + return std::imag(c); } +} // namespace clay #else #define CLAY_ALIGN(n) __attribute__((aligned(n))) namespace clay { - typedef std::complex clay_cfloat; - typedef std::complex clay_cdouble; - typedef std::complex clay_cldouble; +typedef std::complex clay_cfloat; +typedef std::complex clay_cdouble; +typedef std::complex clay_cldouble; - inline float clay_creal(const clay_cfloat &c) { return c.real(); } - inline double clay_creal(const clay_cdouble &c) { return c.real(); } - inline long double clay_creal(const clay_cldouble &c) { return c.real(); } +inline float clay_creal(const clay_cfloat &c) { return c.real(); } +inline double clay_creal(const clay_cdouble &c) { return c.real(); } +inline long double clay_creal(const clay_cldouble &c) { return c.real(); } - inline float clay_cimag(const clay_cfloat &c) { return c.imag(); } - inline double clay_cimag(const clay_cdouble &c) { return c.imag(); } - inline long double clay_cimag(const clay_cldouble &c) { return c.imag(); } -} +inline float clay_cimag(const clay_cfloat &c) { return c.imag(); } +inline double clay_cimag(const clay_cdouble &c) { return c.imag(); } +inline long double clay_cimag(const clay_cldouble &c) { return c.imag(); } +} // namespace clay #endif @@ -137,2739 +148,2394 @@ namespace clay { #define CLAY_COMPILER_VERSION "0.2git" namespace clay { - // - // container typedefs - // - - typedef llvm::SmallString<260> PathString; - - // - // Target-specific types - // - typedef int ptrdiff32_t; - typedef long long ptrdiff64_t; - - typedef unsigned size32_t; - typedef unsigned long long size64_t; - - // - // ObjectKind - // - -#define OBJECT_KIND_MAP(XX) \ - XX(SOURCE) \ - XX(LOCATION) \ -\ - XX(IDENTIFIER) \ - XX(DOTTED_NAME) \ -\ - XX(EXPRESSION) \ - XX(EXPR_LIST) \ - XX(STATEMENT) \ - XX(CASE_BLOCK) \ - XX(CATCH) \ -\ - XX(FORMAL_ARG) \ - XX(RETURN_SPEC) \ - XX(LLVM_CODE) \ - XX(CODE) \ -\ - XX(RECORD_DECL) \ - XX(RECORD_BODY) \ - XX(RECORD_FIELD) \ - XX(VARIANT_DECL) \ - XX(INSTANCE_DECL) \ - XX(NEW_TYPE_DECL) \ - XX(OVERLOAD) \ - XX(PROCEDURE) \ - XX(INTRINSIC) \ - XX(ENUM_DECL) \ - XX(ENUM_MEMBER) \ - XX(GLOBAL_VARIABLE) \ - XX(EXTERNAL_PROCEDURE) \ - XX(EXTERNAL_ARG) \ - XX(EXTERNAL_VARIABLE) \ - XX(EVAL_TOPLEVEL) \ -\ - XX(GLOBAL_ALIAS) \ -\ - XX(IMPORT) \ - XX(MODULE_DECLARATION) \ - XX(MODULE) \ -\ - XX(ENV) \ -\ - XX(PRIM_OP) \ -\ - XX(TYPE) \ -\ - XX(PATTERN) \ - XX(MULTI_PATTERN) \ -\ - XX(VALUE_HOLDER) \ - XX(MULTI_STATIC) \ -\ - XX(PVALUE) \ - XX(MULTI_PVALUE) \ -\ - XX(EVALUE) \ - XX(MULTI_EVALUE) \ -\ - XX(CVALUE) \ - XX(MULTI_CVALUE) \ -\ - XX(DOCUMENTATION) \ -\ +// +// container typedefs +// + +typedef llvm::SmallString<260> PathString; + +// +// Target-specific types +// +typedef int ptrdiff32_t; +typedef long long ptrdiff64_t; + +typedef unsigned size32_t; +typedef unsigned long long size64_t; + +// +// ObjectKind +// + +#define OBJECT_KIND_MAP(XX) \ + XX(SOURCE) \ + XX(LOCATION) \ + \ + XX(IDENTIFIER) \ + XX(DOTTED_NAME) \ + \ + XX(EXPRESSION) \ + XX(EXPR_LIST) \ + XX(STATEMENT) \ + XX(CASE_BLOCK) \ + XX(CATCH) \ + \ + XX(FORMAL_ARG) \ + XX(RETURN_SPEC) \ + XX(LLVM_CODE) \ + XX(CODE) \ + \ + XX(RECORD_DECL) \ + XX(RECORD_BODY) \ + XX(RECORD_FIELD) \ + XX(VARIANT_DECL) \ + XX(INSTANCE_DECL) \ + XX(NEW_TYPE_DECL) \ + XX(OVERLOAD) \ + XX(PROCEDURE) \ + XX(INTRINSIC) \ + XX(ENUM_DECL) \ + XX(ENUM_MEMBER) \ + XX(GLOBAL_VARIABLE) \ + XX(EXTERNAL_PROCEDURE) \ + XX(EXTERNAL_ARG) \ + XX(EXTERNAL_VARIABLE) \ + XX(EVAL_TOPLEVEL) \ + \ + XX(GLOBAL_ALIAS) \ + \ + XX(IMPORT) \ + XX(MODULE_DECLARATION) \ + XX(MODULE) \ + \ + XX(ENV) \ + \ + XX(PRIM_OP) \ + \ + XX(TYPE) \ + \ + XX(PATTERN) \ + XX(MULTI_PATTERN) \ + \ + XX(VALUE_HOLDER) \ + XX(MULTI_STATIC) \ + \ + XX(PVALUE) \ + XX(MULTI_PVALUE) \ + \ + XX(EVALUE) \ + XX(MULTI_EVALUE) \ + \ + XX(CVALUE) \ + XX(MULTI_CVALUE) \ + \ + XX(DOCUMENTATION) \ + \ XX(STATIC_ASSERT_TOP_LEVEL) #define OBJECT_KIND_GEN(e) e, - enum ObjectKind { - OBJECT_KIND_MAP(OBJECT_KIND_GEN) - }; +enum ObjectKind { OBJECT_KIND_MAP(OBJECT_KIND_GEN) }; #undef OBJECT_KIND_GEN - llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ObjectKind); - - // - // Object - // - - struct Object : public RefCounted { - const ObjectKind objKind; +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ObjectKind); + +// +// Object +// + +struct Object : public RefCounted { + const ObjectKind objKind; + + Object(ObjectKind objKind) : objKind(objKind) {} + + virtual ~Object() {} + + // print to stderr, for debugging + void print() const; + + // use only in debugger + std::string toString() const; +}; + +typedef Pointer ObjectPtr; + +// +// forwards +// + +struct Source; + +struct ANode; +struct Identifier; +struct DottedName; + +struct Expr; +struct BoolLiteral; +struct IntLiteral; +struct FloatLiteral; +struct CharLiteral; +struct StringLiteral; +struct NameRef; +struct FILEExpr; +struct LINEExpr; +struct COLUMNExpr; +struct ARGExpr; +struct Tuple; +struct Paren; +struct Indexing; +struct Call; +struct FieldRef; +struct StaticIndexing; +struct VariadicOp; +struct And; +struct Or; +struct Lambda; +struct Unpack; +struct StaticExpr; +struct DispatchExpr; +struct ForeignExpr; +struct ObjectExpr; +struct EvalExpr; + +struct ExprList; + +struct Statement; +struct Block; +struct Label; +struct Binding; +struct Assignment; +struct InitAssignment; +struct VariadicAssignment; +struct Goto; +struct Switch; +struct CaseBlock; +struct Return; +struct If; +struct ExprStatement; +struct While; +struct Break; +struct Continue; +struct For; +struct ForeignStatement; +struct Try; +struct Catch; +struct Throw; +struct StaticFor; +struct Finally; +struct OnError; +struct Unreachable; +struct EvalStatement; +struct StaticAssertStatement; + +struct FormalArg; +struct ReturnSpec; +struct LLVMCode; +struct Code; + +struct TopLevelItem; +struct RecordDecl; +struct RecordBody; +struct RecordField; +struct VariantDecl; +struct InstanceDecl; +struct NewTypeDecl; +struct Overload; +struct Procedure; +struct IntrinsicSymbol; +struct EnumDecl; +struct EnumMember; +struct GlobalVariable; +struct GVarInstance; +struct ExternalProcedure; +struct ExternalArg; +struct ExternalVariable; +struct EvalTopLevel; +struct StaticAssertTopLevel; +struct Documentation; + +struct GlobalAlias; + +struct Import; +struct ImportModule; +struct ImportStar; +struct ImportMembers; +struct Module; +struct ModuleDeclaration; + +struct Env; + +struct PrimOp; + +struct Type; +struct BoolType; +struct IntegerType; +struct FloatType; +struct ComplexType; +struct ArrayType; +struct VecType; +struct TupleType; +struct UnionType; +struct PointerType; +struct CodePointerType; +struct CCodePointerType; +struct RecordType; +struct VariantType; +struct StaticType; +struct EnumType; +struct NewType; + +struct Pattern; +struct PatternCell; +struct PatternStruct; + +struct MultiPattern; +struct MultiPatternCell; +struct MultiPatternList; + +struct ValueHolder; +struct MultiStatic; + +struct PValue; +struct MultiPValue; + +struct EValue; +struct MultiEValue; + +struct CValue; +struct MultiCValue; + +struct ObjectTable; + +struct ValueStackEntry; + +struct MatchResult; +struct MatchFailureError; + +// +// Pointer typedefs +// + +typedef Pointer SourcePtr; + +typedef Pointer ANodePtr; +typedef Pointer IdentifierPtr; +typedef Pointer DottedNamePtr; + +typedef Pointer ExprPtr; +typedef Pointer BoolLiteralPtr; +typedef Pointer IntLiteralPtr; +typedef Pointer FloatLiteralPtr; +typedef Pointer CharLiteralPtr; +typedef Pointer StringLiteralPtr; +typedef Pointer NameRefPtr; +typedef Pointer FILEExprPtr; +typedef Pointer LINEExprPtr; +typedef Pointer COLUMNExprPtr; +typedef Pointer ARGExprPtr; +typedef Pointer TuplePtr; +typedef Pointer ParenPtr; +typedef Pointer IndexingPtr; +typedef Pointer CallPtr; +typedef Pointer FieldRefPtr; +typedef Pointer StaticIndexingPtr; +typedef Pointer VariadicOpPtr; +typedef Pointer AndPtr; +typedef Pointer OrPtr; +typedef Pointer LambdaPtr; +typedef Pointer UnpackPtr; +typedef Pointer StaticExprPtr; +typedef Pointer DispatchExprPtr; +typedef Pointer ForeignExprPtr; +typedef Pointer ObjectExprPtr; +typedef Pointer EvalExprPtr; + +typedef Pointer ExprListPtr; + +typedef Pointer StatementPtr; +typedef Pointer BlockPtr; +typedef Pointer