slang_rs.cpp revision fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0
1c383a500aa59423264811be3874461bf8adbfea0Zonr Chang/* 20a813a3ef2a82f19d7eab9e23ae8493197143803Stephen Hines * Copyright 2010-2012, The Android Open Source Project 3c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * 4c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * Licensed under the Apache License, Version 2.0 (the "License"); 5c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * you may not use this file except in compliance with the License. 6c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * You may obtain a copy of the License at 7c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * 8c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * http://www.apache.org/licenses/LICENSE-2.0 9c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * 10c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * Unless required by applicable law or agreed to in writing, software 11c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * distributed under the License is distributed on an "AS IS" BASIS, 12c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * See the License for the specific language governing permissions and 14c383a500aa59423264811be3874461bf8adbfea0Zonr Chang * limitations under the License. 15c383a500aa59423264811be3874461bf8adbfea0Zonr Chang */ 16c383a500aa59423264811be3874461bf8adbfea0Zonr Chang 173a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "slang_rs.h" 183a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 19b81c6a4cbd9c08e0b20ea4fbc615b416ac1bc9ecShih-wei Liao#include <cstring> 20e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines#include <list> 212e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines#include <sstream> 22e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines#include <string> 23e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines#include <utility> 24e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines#include <vector> 25fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines 26be27482cdeaf08576bc39b72a15d35d13014a636Logan#include "clang/Basic/SourceLocation.h" 27be27482cdeaf08576bc39b72a15d35d13014a636Logan 28cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang#include "clang/Frontend/FrontendDiagnostic.h" 29cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 303a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "clang/Sema/SemaDiagnostic.h" 313a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 32be27482cdeaf08576bc39b72a15d35d13014a636Logan#include "llvm/Support/Path.h" 33e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines 348d5a2f6ab321615bfb3a46f68aff0b643a71caa0Raphael#include "os_sep.h" 357f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines#include "rs_cc_options.h" 363a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "slang_rs_backend.h" 373a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "slang_rs_context.h" 38641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang#include "slang_rs_export_type.h" 393a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 4012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet#include "slang_rs_reflection.h" 411b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams#include "slang_rs_reflection_cpp.h" 421b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams 43e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hinesnamespace slang { 443a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 4511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines#define FS_SUFFIX "fs" 4611274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines 473c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang#define RS_HEADER_SUFFIX "rsh" 483c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang 492d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines/* RS_HEADER_ENTRY(name) */ 503c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang#define ENUM_RS_HEADER() \ 512d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_allocation) \ 522d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_atomic) \ 532d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_cl) \ 542d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_core) \ 55a7ab54d590b5a959354a654cccacf4337e7fd5b0Stephen Hines RS_HEADER_ENTRY(rs_core_math) \ 562d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_debug) \ 574eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_element) \ 582d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_graphics) \ 592d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_math) \ 604eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_mesh) \ 612d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_matrix) \ 622d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_object) \ 634eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_program) \ 642d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_quaternion) \ 654eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_sampler) \ 662d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_time) \ 672d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_types) \ 682d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines 6911274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines// Returns true if \p Filename ends in ".fs". 7011274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hinesbool SlangRS::isFilterscript(const char *Filename) { 7111274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines const char *c = strrchr(Filename, '.'); 7211274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) { 7311274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines return true; 7411274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines } else { 7511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines return false; 7611274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines } 7711274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines} 783c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang 79129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouilletbool SlangRS::generateJavaBitcodeAccessor(const std::string &OutputPathBase, 8012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet const std::string &PackageName, 8112fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet const std::string *LicenseNote) { 82cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 83cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 84cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.rsFileName = getInputFileName().c_str(); 85cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.bcFileName = getOutputFileName().c_str(); 86cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.reflectPath = OutputPathBase.c_str(); 87cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.packageName = PackageName.c_str(); 88129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet BCAccessorContext.licenseNote = LicenseNote; 89cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 90cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 91129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet return RSSlangReflectUtils::GenerateJavaBitCodeAccessor(BCAccessorContext); 92cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang} 93cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 94e86245a09bb8b9e72f5dc68083444ec938865798Zonr Changbool SlangRS::checkODR(const char *CurInputFile) { 95641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 96641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang E = mRSContext->exportable_end(); 97641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I != E; 98641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I++) { 99a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines RSExportable *RSE = *I; 100a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines if (RSE->getKind() != RSExportable::EX_TYPE) 101641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 102641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 103a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines RSExportType *ET = static_cast<RSExportType *>(RSE); 104641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (ET->getClass() != RSExportType::ExportClassRecord) 105641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 106641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 107641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 108641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 109641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Artificial record types (create by us not by user in the source) always 110641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // conforms the ODR. 111641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (ERT->isArtificial()) 112641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 113641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 114641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Key to lookup ERT in ReflectedDefinitions 115641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringRef RDKey(ERT->getName()); 116641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ReflectedDefinitionListTy::const_iterator RD = 117641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ReflectedDefinitions.find(RDKey); 118641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 119641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (RD != ReflectedDefinitions.end()) { 120641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang const RSExportRecordType *Reflected = RD->getValue().first; 121641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // There's a record (struct) with the same name reflected before. Enforce 122641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // ODR checking - the Reflected must hold *exactly* the same "definition" 123641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // as the one defined previously. We say two record types A and B have the 124641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // same definition iff: 125641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // 126641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // struct A { struct B { 127641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(a1) a1, Type(b1) b1, 128641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(a2) a2, Type(b1) b2, 129641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // ... ... 130641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(aN) aN Type(b3) b3, 131641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // }; } 132641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #1. They have same number of fields, i.e., N = M; 133641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #2. for (i := 1 to N) 134641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(ai) = Type(bi) must hold; 135641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #3. for (i := 1 to N) 136641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Name(ai) = Name(bi) must hold; 137641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // 138641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // where, 139641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(F) = the type of field F and 140641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Name(F) = the field name. 141641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 142641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang bool PassODR = false; 143641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #1 and Cond. #2 144641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (Reflected->equals(ERT)) { 145641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond #3. 146641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 147641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang BI = ERT->fields_begin(); 148641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 149641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 150641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if ((*AI)->getName() != (*BI)->getName()) 151641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang break; 152641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang AI++; 153641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang BI++; 154641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 155641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang PassODR = (AI == (Reflected->fields_end())); 156641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 157641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 158641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (!PassODR) { 159641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 160641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang << getInputFileName() 161641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang << RD->getValue().second; 162641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return false; 163641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 164641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } else { 165641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 166641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 167641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RDKey.end()); 168e86245a09bb8b9e72f5dc68083444ec938865798Zonr Chang ME->setValue(std::make_pair(ERT, CurInputFile)); 169641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 170641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (!ReflectedDefinitions.insert(ME)) 171641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete ME; 172641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 173641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Take the ownership of ERT such that it won't be freed in ~RSContext(). 174641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ERT->keep(); 175641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 176641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 177641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return true; 178641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang} 179cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 1803a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initDiagnostic() { 1819207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine &DiagEngine = getDiagnostics(); 182cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 1839207a2e495c8363606861e4f034504ec5c153dabLogan Chien if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration", 1849207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::MAP_ERROR)) 1859207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.Report(clang::diag::warn_unknown_warning_option) 1869207a2e495c8363606861e4f034504ec5c153dabLogan Chien << "implicit-function-declaration"; 1879207a2e495c8363606861e4f034504ec5c153dabLogan Chien 1889207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.setDiagnosticMapping( 1899207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::ext_typecheck_convert_discards_qualifiers, 1909207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::MAP_ERROR, 1919207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::SourceLocation()); 192641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 193641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mDiagErrorInvalidOutputDepParameter = 1949207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 1959207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 1969207a2e495c8363606861e4f034504ec5c153dabLogan Chien "invalid parameter for output dependencies files."); 197641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 198641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mDiagErrorODR = 1999207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 2009207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 2019207a2e495c8363606861e4f034504ec5c153dabLogan Chien "type '%0' in different translation unit (%1 v.s. %2) " 2029207a2e495c8363606861e4f034504ec5c153dabLogan Chien "has incompatible type definition"); 2039207a2e495c8363606861e4f034504ec5c153dabLogan Chien 2049207a2e495c8363606861e4f034504ec5c153dabLogan Chien mDiagErrorTargetAPIRange = 2059207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 2069207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 2072e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines "target API level '%0' is out of range ('%1' - '%2')"); 2083a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2093a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2103a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initPreprocessor() { 2113a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang clang::Preprocessor &PP = getPreprocessor(); 2123a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2132e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines std::stringstream RSH; 2140e4ee65a2ba6b32fcd16c5d4a57fc7542d4032b4Stephen Hines RSH << PP.getPredefines(); 2152968921e1cedf85360964c5a39e1ce36c66ecd09Jean-Luc Brouillet RSH << "#define RS_VERSION " << mTargetAPI << "\n"; 2162968921e1cedf85360964c5a39e1ce36c66ecd09Jean-Luc Brouillet RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"\n"; 2172e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines PP.setPredefines(RSH.str()); 2183a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2193a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2203a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initASTContext() { 2219e5b503349719144f63ccb7c62ee9c291a7d83b8Stephen Hines mRSContext = new RSContext(getPreprocessor(), 2229e5b503349719144f63ccb7c62ee9c291a7d83b8Stephen Hines getASTContext(), 2233fd0a94a5cf1656569b1aea07043cc63939dcb46Stephen Hines getTargetInfo(), 2244cc67fce91f43215d61b2695746eab102a3db516Stephen Hines &mPragmas, 225fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0Stephen Hines mTargetAPI, 226fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0Stephen Hines mVerbose); 2273a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2283a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2293a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changclang::ASTConsumer 2303a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 2313a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang llvm::raw_ostream *OS, 2323a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang Slang::OutputType OT) { 2333a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang return new RSBackend(mRSContext, 234e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines &getDiagnostics(), 2353a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang CodeGenOpts, 2363a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang getTargetOptions(), 2373fd0a94a5cf1656569b1aea07043cc63939dcb46Stephen Hines &mPragmas, 2383a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang OS, 2393a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang OT, 2403a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang getSourceManager(), 24111274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mAllowRSPrefix, 24211274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mIsFilterscript); 2433a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2443a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 245592a954aae4cb946970b557e94afd5ee453fd57eZonr Changbool SlangRS::IsRSHeaderFile(const char *File) { 2462d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines#define RS_HEADER_ENTRY(name) \ 247ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray if (::strcmp(File, #name "." RS_HEADER_SUFFIX) == 0) \ 248592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang return true; 249592a954aae4cb946970b557e94afd5ee453fd57eZonr ChangENUM_RS_HEADER() 250592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang#undef RS_HEADER_ENTRY 251592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang return false; 252592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang} 253592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang 25411274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hinesbool SlangRS::IsLocInRSHeaderFile(const clang::SourceLocation &Loc, 25511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines const clang::SourceManager &SourceMgr) { 25611274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines clang::FullSourceLoc FSL(Loc, SourceMgr); 257fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 258fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines 259688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines const char *Filename = PLoc.getFilename(); 260688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines if (!Filename) { 261688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines return false; 262688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines } else { 263688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines return IsRSHeaderFile(llvm::sys::path::filename(Filename).data()); 264688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines } 265fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines} 266fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines 2679207a2e495c8363606861e4f034504ec5c153dabLogan ChienSlangRS::SlangRS() 26811274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0), 269fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0Stephen Hines mVerbose(false), mIsFilterscript(false) { 2703a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2713a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 272cf6af6abc1de499920571308b14a27e19cf57097Zonr Changbool SlangRS::compile( 273cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::list<std::pair<const char*, const char*> > &IOFiles, 274cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::list<std::pair<const char*, const char*> > &DepFiles, 2757f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines const RSCCOptions &Opts) { 276cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (IOFiles.empty()) 277cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return true; 278cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 2797f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (Opts.mEmitDependency && (DepFiles.size() != IOFiles.size())) { 280641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 2813a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang return false; 282cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 2833a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 284cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang std::string RealPackageName; 285cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 286cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 287cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang std::list<std::pair<const char*, const char*> >::const_iterator 288cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 289cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 2907f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines setIncludePaths(Opts.mIncludePaths); 2917f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines setOutputType(Opts.mOutputType); 2927f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (Opts.mEmitDependency) { 2937f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines setAdditionalDepTargets(Opts.mAdditionalDepTargets); 2944cc67fce91f43215d61b2695746eab102a3db516Stephen Hines } 295cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 2967f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines setDebugMetadataEmission(Opts.mDebugEmission); 297c460b37ffb50819a32c2a8967754b6f784b28263mkopec 2987f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines setOptimizationLevel(Opts.mOptimizationLevel); 299c460b37ffb50819a32c2a8967754b6f784b28263mkopec 3007f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines mAllowRSPrefix = Opts.mAllowRSPrefix; 301cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3027f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines mTargetAPI = Opts.mTargetAPI; 3034cc499d6e5ec602309501873449c938af61170b2Stephen Hines if (mTargetAPI < SLANG_MINIMUM_TARGET_API || 3044cc499d6e5ec602309501873449c938af61170b2Stephen Hines mTargetAPI > SLANG_MAXIMUM_TARGET_API) { 3052e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI 3064cc499d6e5ec602309501873449c938af61170b2Stephen Hines << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API; 3072e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines return false; 3082e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines } 3092e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines 310fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0Stephen Hines mVerbose = Opts.mVerbose; 311fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0Stephen Hines 312c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines // Skip generation of warnings a second time if we are doing more than just 313c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines // a single pass over the input file. 3147f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines bool SuppressAllWarnings = (Opts.mOutputType != Slang::OT_Dependency); 315c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines 316cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 317cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang InputFile = IOFileIter->first; 318cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang OutputFile = IOFileIter->second; 319cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 320cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang reset(); 321cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 322cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (!setInputSource(InputFile)) 323cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 324cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 325cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (!setOutput(OutputFile)) 326cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 327cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 32811274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mIsFilterscript = isFilterscript(InputFile); 32911274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines 330cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (Slang::compile() > 0) 331cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 332cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3337f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (!Opts.mJavaReflectionPackageName.empty()) { 3347f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines mRSContext->setReflectJavaPackageName(Opts.mJavaReflectionPackageName); 335925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines } 336925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines const std::string &RealPackageName = 337925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines mRSContext->getReflectJavaPackageName(); 338925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines 3397f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (Opts.mOutputType != Slang::OT_Dependency) { 340cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3417f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (Opts.mBitcodeStorage == BCST_CPP_CODE) { 3427f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines RSReflectionCpp R(mRSContext, Opts.mJavaReflectionPathBase, 3437f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines getInputFileName(), getOutputFileName()); 34459f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet if (!R.reflect()) { 3451b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams return false; 3461b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams } 3475c25c5159c0a5be9af992679067790716626da7bStephen Hines } else { 3487f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (!Opts.mRSPackageName.empty()) { 3497f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines mRSContext->setRSPackageName(Opts.mRSPackageName); 35012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet } 3514cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 35259f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet RSReflectionJava R(mRSContext, &mGeneratedFileNames, 3537f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines Opts.mJavaReflectionPathBase, getInputFileName(), 35459f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet getOutputFileName(), 3557f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines Opts.mBitcodeStorage == BCST_JAVA_CODE); 35659f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet if (!R.reflect()) { 35712fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet // TODO Is this needed or will the error message have been printed 35812fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet // already? and why not for the C++ case? 35912fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet fprintf(stderr, "RSContext::reflectToJava : failed to do reflection " 36012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet "(%s)\n", 36112fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet R.getLastError()); 3627fda9848f91fc5cca55f63423b35672128b6daabJean-Luc Brouillet return false; 3635c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3645c25c5159c0a5be9af992679067790716626da7bStephen Hines 3655c25c5159c0a5be9af992679067790716626da7bStephen Hines for (std::vector<std::string>::const_iterator 3665c25c5159c0a5be9af992679067790716626da7bStephen Hines I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end(); 3675c25c5159c0a5be9af992679067790716626da7bStephen Hines I != E; 3685c25c5159c0a5be9af992679067790716626da7bStephen Hines I++) { 3695c25c5159c0a5be9af992679067790716626da7bStephen Hines std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath( 3707f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines Opts.mJavaReflectionPathBase.c_str(), 3715c25c5159c0a5be9af992679067790716626da7bStephen Hines (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str()); 3725c25c5159c0a5be9af992679067790716626da7bStephen Hines appendGeneratedFileName(ReflectedName + ".java"); 3735c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3745c25c5159c0a5be9af992679067790716626da7bStephen Hines 3757f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if ((Opts.mOutputType == Slang::OT_Bitcode) && 3767f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines (Opts.mBitcodeStorage == BCST_JAVA_CODE) && 3777f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines !generateJavaBitcodeAccessor(Opts.mJavaReflectionPathBase, 378129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet RealPackageName.c_str(), 379129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet mRSContext->getLicenseNote())) { 3805c25c5159c0a5be9af992679067790716626da7bStephen Hines return false; 3815c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3825c25c5159c0a5be9af992679067790716626da7bStephen Hines } 383cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 384cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3857f5704efe0c59d5599f1ac7056976225dbfab946Stephen Hines if (Opts.mEmitDependency) { 3864cc67fce91f43215d61b2695746eab102a3db516Stephen Hines BCOutputFile = DepFileIter->first; 3874cc67fce91f43215d61b2695746eab102a3db516Stephen Hines DepOutputFile = DepFileIter->second; 3884cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 3894cc67fce91f43215d61b2695746eab102a3db516Stephen Hines setDepTargetBC(BCOutputFile); 3904cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 3914cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (!setDepOutput(DepOutputFile)) 3924cc67fce91f43215d61b2695746eab102a3db516Stephen Hines return false; 3934cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 394c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines if (SuppressAllWarnings) { 395c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines getDiagnostics().setSuppressAllDiagnostics(true); 396c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines } 3974cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (generateDepFile() > 0) 3984cc67fce91f43215d61b2695746eab102a3db516Stephen Hines return false; 399c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines if (SuppressAllWarnings) { 400c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines getDiagnostics().setSuppressAllDiagnostics(false); 401c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines } 4024cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 4034cc67fce91f43215d61b2695746eab102a3db516Stephen Hines DepFileIter++; 4044cc67fce91f43215d61b2695746eab102a3db516Stephen Hines } 4054cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 406e86245a09bb8b9e72f5dc68083444ec938865798Zonr Chang if (!checkODR(InputFile)) 407641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return false; 408641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 409cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang IOFileIter++; 410cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 411cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 412cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return true; 4133a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 4143a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 415641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Changvoid SlangRS::reset() { 416641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete mRSContext; 417641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mRSContext = NULL; 4184cc67fce91f43215d61b2695746eab102a3db516Stephen Hines mGeneratedFileNames.clear(); 419641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang Slang::reset(); 420641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang} 421641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 4223a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr ChangSlangRS::~SlangRS() { 4233a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang delete mRSContext; 424641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 425641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang E = ReflectedDefinitions.end(); 426641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I != E; 427641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I++) { 428641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete I->getValue().first; 429641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 4303a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 431e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines 432e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines} // namespace slang 433