slang_rs.cpp revision 59f22c376b2c1cd109735280689224fadfe40b42
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" 353a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "slang_rs_backend.h" 363a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang#include "slang_rs_context.h" 37641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang#include "slang_rs_export_type.h" 383a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 3912fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet#include "slang_rs_reflection.h" 401b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams#include "slang_rs_reflection_cpp.h" 411b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams 42e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hinesnamespace slang { 433a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 4411274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines#define FS_SUFFIX "fs" 4511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines 463c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang#define RS_HEADER_SUFFIX "rsh" 473c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang 482d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines/* RS_HEADER_ENTRY(name) */ 493c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang#define ENUM_RS_HEADER() \ 502d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_allocation) \ 512d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_atomic) \ 522d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_cl) \ 532d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_core) \ 54a7ab54d590b5a959354a654cccacf4337e7fd5b0Stephen Hines RS_HEADER_ENTRY(rs_core_math) \ 552d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_debug) \ 564eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_element) \ 572d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_graphics) \ 582d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_math) \ 594eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_mesh) \ 602d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_matrix) \ 612d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_object) \ 624eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_program) \ 632d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_quaternion) \ 644eb4b38b35855436543d229bc3c83b60d47dbbceAlex Sakhartchouk RS_HEADER_ENTRY(rs_sampler) \ 652d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_time) \ 662d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines RS_HEADER_ENTRY(rs_types) \ 672d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines 6811274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines// Returns true if \p Filename ends in ".fs". 6911274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hinesbool SlangRS::isFilterscript(const char *Filename) { 7011274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines const char *c = strrchr(Filename, '.'); 7111274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) { 7211274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines return true; 7311274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines } else { 7411274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines return false; 7511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines } 7611274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines} 773c250c5d6cbf4123e959a3466990fda9fa50987aZonr Chang 78129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouilletbool SlangRS::generateJavaBitcodeAccessor(const std::string &OutputPathBase, 7912fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet const std::string &PackageName, 8012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet const std::string *LicenseNote) { 81cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 82cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 83cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.rsFileName = getInputFileName().c_str(); 84cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.bcFileName = getOutputFileName().c_str(); 85cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.reflectPath = OutputPathBase.c_str(); 86cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.packageName = PackageName.c_str(); 87129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet BCAccessorContext.licenseNote = LicenseNote; 88cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 89cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 90129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet return RSSlangReflectUtils::GenerateJavaBitCodeAccessor(BCAccessorContext); 91cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang} 92cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 93e86245a09bb8b9e72f5dc68083444ec938865798Zonr Changbool SlangRS::checkODR(const char *CurInputFile) { 94641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 95641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang E = mRSContext->exportable_end(); 96641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I != E; 97641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I++) { 98a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines RSExportable *RSE = *I; 99a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines if (RSE->getKind() != RSExportable::EX_TYPE) 100641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 101641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 102a858cb6f3d9223d65bf73e1230c6324ded4095f6Stephen Hines RSExportType *ET = static_cast<RSExportType *>(RSE); 103641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (ET->getClass() != RSExportType::ExportClassRecord) 104641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 105641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 106641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 107641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 108641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Artificial record types (create by us not by user in the source) always 109641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // conforms the ODR. 110641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (ERT->isArtificial()) 111641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang continue; 112641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 113641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Key to lookup ERT in ReflectedDefinitions 114641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringRef RDKey(ERT->getName()); 115641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ReflectedDefinitionListTy::const_iterator RD = 116641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ReflectedDefinitions.find(RDKey); 117641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 118641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (RD != ReflectedDefinitions.end()) { 119641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang const RSExportRecordType *Reflected = RD->getValue().first; 120641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // There's a record (struct) with the same name reflected before. Enforce 121641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // ODR checking - the Reflected must hold *exactly* the same "definition" 122641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // as the one defined previously. We say two record types A and B have the 123641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // same definition iff: 124641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // 125641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // struct A { struct B { 126641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(a1) a1, Type(b1) b1, 127641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(a2) a2, Type(b1) b2, 128641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // ... ... 129641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(aN) aN Type(b3) b3, 130641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // }; } 131641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #1. They have same number of fields, i.e., N = M; 132641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #2. for (i := 1 to N) 133641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(ai) = Type(bi) must hold; 134641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #3. for (i := 1 to N) 135641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Name(ai) = Name(bi) must hold; 136641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // 137641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // where, 138641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Type(F) = the type of field F and 139641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Name(F) = the field name. 140641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 141641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang bool PassODR = false; 142641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond. #1 and Cond. #2 143641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (Reflected->equals(ERT)) { 144641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Cond #3. 145641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 146641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang BI = ERT->fields_begin(); 147641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 148641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 149641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if ((*AI)->getName() != (*BI)->getName()) 150641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang break; 151641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang AI++; 152641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang BI++; 153641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 154641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang PassODR = (AI == (Reflected->fields_end())); 155641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 156641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 157641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (!PassODR) { 158641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 159641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang << getInputFileName() 160641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang << RD->getValue().second; 161641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return false; 162641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 163641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } else { 164641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 165641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 166641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang RDKey.end()); 167e86245a09bb8b9e72f5dc68083444ec938865798Zonr Chang ME->setValue(std::make_pair(ERT, CurInputFile)); 168641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 169641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang if (!ReflectedDefinitions.insert(ME)) 170641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete ME; 171641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 172641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang // Take the ownership of ERT such that it won't be freed in ~RSContext(). 173641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang ERT->keep(); 174641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 175641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 176641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return true; 177641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang} 178cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 1793a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initDiagnostic() { 1809207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine &DiagEngine = getDiagnostics(); 181cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 1829207a2e495c8363606861e4f034504ec5c153dabLogan Chien if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration", 1839207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::MAP_ERROR)) 1849207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.Report(clang::diag::warn_unknown_warning_option) 1859207a2e495c8363606861e4f034504ec5c153dabLogan Chien << "implicit-function-declaration"; 1869207a2e495c8363606861e4f034504ec5c153dabLogan Chien 1879207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.setDiagnosticMapping( 1889207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::ext_typecheck_convert_discards_qualifiers, 1899207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::diag::MAP_ERROR, 1909207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::SourceLocation()); 191641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 192641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mDiagErrorInvalidOutputDepParameter = 1939207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 1949207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 1959207a2e495c8363606861e4f034504ec5c153dabLogan Chien "invalid parameter for output dependencies files."); 196641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 197641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mDiagErrorODR = 1989207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 1999207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 2009207a2e495c8363606861e4f034504ec5c153dabLogan Chien "type '%0' in different translation unit (%1 v.s. %2) " 2019207a2e495c8363606861e4f034504ec5c153dabLogan Chien "has incompatible type definition"); 2029207a2e495c8363606861e4f034504ec5c153dabLogan Chien 2039207a2e495c8363606861e4f034504ec5c153dabLogan Chien mDiagErrorTargetAPIRange = 2049207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine.getCustomDiagID( 2059207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine::Error, 2062e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines "target API level '%0' is out of range ('%1' - '%2')"); 2073a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2083a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2093a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initPreprocessor() { 2103a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang clang::Preprocessor &PP = getPreprocessor(); 2113a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2122e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines std::stringstream RSH; 2132968921e1cedf85360964c5a39e1ce36c66ecd09Jean-Luc Brouillet RSH << "#define RS_VERSION " << mTargetAPI << "\n"; 2142968921e1cedf85360964c5a39e1ce36c66ecd09Jean-Luc Brouillet RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"\n"; 2152e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines PP.setPredefines(RSH.str()); 2163a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2173a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2183a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changvoid SlangRS::initASTContext() { 2199e5b503349719144f63ccb7c62ee9c291a7d83b8Stephen Hines mRSContext = new RSContext(getPreprocessor(), 2209e5b503349719144f63ccb7c62ee9c291a7d83b8Stephen Hines getASTContext(), 2213fd0a94a5cf1656569b1aea07043cc63939dcb46Stephen Hines getTargetInfo(), 2224cc67fce91f43215d61b2695746eab102a3db516Stephen Hines &mPragmas, 22312fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet mTargetAPI); 2243a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2253a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 2263a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Changclang::ASTConsumer 2273a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 2283a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang llvm::raw_ostream *OS, 2293a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang Slang::OutputType OT) { 2303a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang return new RSBackend(mRSContext, 231e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines &getDiagnostics(), 2323a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang CodeGenOpts, 2333a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang getTargetOptions(), 2343fd0a94a5cf1656569b1aea07043cc63939dcb46Stephen Hines &mPragmas, 2353a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang OS, 2363a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang OT, 2373a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang getSourceManager(), 23811274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mAllowRSPrefix, 23911274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mIsFilterscript); 2403a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2413a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 242592a954aae4cb946970b557e94afd5ee453fd57eZonr Changbool SlangRS::IsRSHeaderFile(const char *File) { 2432d35eddd17eaa8bf5a0202dc60ead14dd16eb2d6Stephen Hines#define RS_HEADER_ENTRY(name) \ 244ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray if (::strcmp(File, #name "." RS_HEADER_SUFFIX) == 0) \ 245592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang return true; 246592a954aae4cb946970b557e94afd5ee453fd57eZonr ChangENUM_RS_HEADER() 247592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang#undef RS_HEADER_ENTRY 248592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang return false; 249592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang} 250592a954aae4cb946970b557e94afd5ee453fd57eZonr Chang 25111274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hinesbool SlangRS::IsLocInRSHeaderFile(const clang::SourceLocation &Loc, 25211274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines const clang::SourceManager &SourceMgr) { 25311274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines clang::FullSourceLoc FSL(Loc, SourceMgr); 254fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 255fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines 256688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines const char *Filename = PLoc.getFilename(); 257688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines if (!Filename) { 258688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines return false; 259688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines } else { 260688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines return IsRSHeaderFile(llvm::sys::path::filename(Filename).data()); 261688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines } 262fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines} 263fcda2352b9e140529f8f3c89f05b10a70c0048b2Stephen Hines 2649207a2e495c8363606861e4f034504ec5c153dabLogan ChienSlangRS::SlangRS() 26511274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0), 26611274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mIsFilterscript(false) { 2673a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 2683a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 269cf6af6abc1de499920571308b14a27e19cf57097Zonr Changbool SlangRS::compile( 270cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::list<std::pair<const char*, const char*> > &IOFiles, 271cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::list<std::pair<const char*, const char*> > &DepFiles, 272cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::vector<std::string> &IncludePaths, 273cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::vector<std::string> &AdditionalDepTargets, 274cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 275cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang bool AllowRSPrefix, bool OutputDep, 276c460b37ffb50819a32c2a8967754b6f784b28263mkopec unsigned int TargetAPI, bool EmitDebug, 277c460b37ffb50819a32c2a8967754b6f784b28263mkopec llvm::CodeGenOpt::Level OptimizationLevel, 278cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const std::string &JavaReflectionPathBase, 2790a813a3ef2a82f19d7eab9e23ae8493197143803Stephen Hines const std::string &JavaReflectionPackageName, 2800a813a3ef2a82f19d7eab9e23ae8493197143803Stephen Hines const std::string &RSPackageName) { 281cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (IOFiles.empty()) 282cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return true; 283cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 284cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (OutputDep && (DepFiles.size() != IOFiles.size())) { 285641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 2863a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang return false; 287cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 2883a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 289cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang std::string RealPackageName; 290cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 291cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 292cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang std::list<std::pair<const char*, const char*> >::const_iterator 293cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 294cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 295cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang setIncludePaths(IncludePaths); 296cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang setOutputType(OutputType); 2974cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (OutputDep) { 298cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang setAdditionalDepTargets(AdditionalDepTargets); 2994cc67fce91f43215d61b2695746eab102a3db516Stephen Hines } 300cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 301c460b37ffb50819a32c2a8967754b6f784b28263mkopec setDebugMetadataEmission(EmitDebug); 302c460b37ffb50819a32c2a8967754b6f784b28263mkopec 303c460b37ffb50819a32c2a8967754b6f784b28263mkopec setOptimizationLevel(OptimizationLevel); 304c460b37ffb50819a32c2a8967754b6f784b28263mkopec 305cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang mAllowRSPrefix = AllowRSPrefix; 306cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3072e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines mTargetAPI = TargetAPI; 3084cc499d6e5ec602309501873449c938af61170b2Stephen Hines if (mTargetAPI < SLANG_MINIMUM_TARGET_API || 3094cc499d6e5ec602309501873449c938af61170b2Stephen Hines mTargetAPI > SLANG_MAXIMUM_TARGET_API) { 3102e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI 3114cc499d6e5ec602309501873449c938af61170b2Stephen Hines << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API; 3122e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines return false; 3132e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines } 3142e35b136cc2434080fcd682d2f95e53a87675dd4Stephen Hines 315c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines // Skip generation of warnings a second time if we are doing more than just 316c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines // a single pass over the input file. 317c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines bool SuppressAllWarnings = (OutputType != Slang::OT_Dependency); 318c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines 319cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 320cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang InputFile = IOFileIter->first; 321cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang OutputFile = IOFileIter->second; 322cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 323cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang reset(); 324cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 325cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (!setInputSource(InputFile)) 326cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 327cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 328cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (!setOutput(OutputFile)) 329cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 330cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 33111274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines mIsFilterscript = isFilterscript(InputFile); 33211274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines 333cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (Slang::compile() > 0) 334cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return false; 335cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 336925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines if (!JavaReflectionPackageName.empty()) { 337925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines mRSContext->setReflectJavaPackageName(JavaReflectionPackageName); 338925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines } 339925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines const std::string &RealPackageName = 340925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines mRSContext->getReflectJavaPackageName(); 341925879fa622dda293806ed25b1ee63d2f4a8d65aStephen Hines 342cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang if (OutputType != Slang::OT_Dependency) { 343cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3445c25c5159c0a5be9af992679067790716626da7bStephen Hines if (BitcodeStorage == BCST_CPP_CODE) { 34559f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet RSReflectionCpp R(mRSContext, JavaReflectionPathBase, getInputFileName(), 34659f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet getOutputFileName()); 34759f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet if (!R.reflect()) { 3481b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams return false; 3491b6a0883cd6984e11e59b0c847fb334df1f41afcJason Sams } 3505c25c5159c0a5be9af992679067790716626da7bStephen Hines } else { 35112fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet if (!RSPackageName.empty()) { 35212fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet mRSContext->setRSPackageName(RSPackageName); 35312fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet } 3544cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 35559f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet RSReflectionJava R(mRSContext, &mGeneratedFileNames, 35659f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet JavaReflectionPathBase, getInputFileName(), 35759f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet getOutputFileName(), 35859f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet BitcodeStorage == BCST_JAVA_CODE); 35959f22c376b2c1cd109735280689224fadfe40b42Jean-Luc Brouillet if (!R.reflect()) { 36012fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet // TODO Is this needed or will the error message have been printed 36112fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet // already? and why not for the C++ case? 36212fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet fprintf(stderr, "RSContext::reflectToJava : failed to do reflection " 36312fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet "(%s)\n", 36412fc283f4108fd6f7f0164c121ff2f6fb5044225Jean-Luc Brouillet R.getLastError()); 3657fda9848f91fc5cca55f63423b35672128b6daabJean-Luc Brouillet return false; 3665c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3675c25c5159c0a5be9af992679067790716626da7bStephen Hines 3685c25c5159c0a5be9af992679067790716626da7bStephen Hines for (std::vector<std::string>::const_iterator 3695c25c5159c0a5be9af992679067790716626da7bStephen Hines I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end(); 3705c25c5159c0a5be9af992679067790716626da7bStephen Hines I != E; 3715c25c5159c0a5be9af992679067790716626da7bStephen Hines I++) { 3725c25c5159c0a5be9af992679067790716626da7bStephen Hines std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath( 3735c25c5159c0a5be9af992679067790716626da7bStephen Hines JavaReflectionPathBase.c_str(), 3745c25c5159c0a5be9af992679067790716626da7bStephen Hines (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str()); 3755c25c5159c0a5be9af992679067790716626da7bStephen Hines appendGeneratedFileName(ReflectedName + ".java"); 3765c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3775c25c5159c0a5be9af992679067790716626da7bStephen Hines 3785c25c5159c0a5be9af992679067790716626da7bStephen Hines if ((OutputType == Slang::OT_Bitcode) && 3795c25c5159c0a5be9af992679067790716626da7bStephen Hines (BitcodeStorage == BCST_JAVA_CODE) && 380129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet !generateJavaBitcodeAccessor(JavaReflectionPathBase, 381129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet RealPackageName.c_str(), 382129fd8228cd04592a20c3d5009805a23585f2479Jean-Luc Brouillet mRSContext->getLicenseNote())) { 3835c25c5159c0a5be9af992679067790716626da7bStephen Hines return false; 3845c25c5159c0a5be9af992679067790716626da7bStephen Hines } 3855c25c5159c0a5be9af992679067790716626da7bStephen Hines } 386cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 387cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 3884cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (OutputDep) { 3894cc67fce91f43215d61b2695746eab102a3db516Stephen Hines BCOutputFile = DepFileIter->first; 3904cc67fce91f43215d61b2695746eab102a3db516Stephen Hines DepOutputFile = DepFileIter->second; 3914cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 3924cc67fce91f43215d61b2695746eab102a3db516Stephen Hines setDepTargetBC(BCOutputFile); 3934cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 3944cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (!setDepOutput(DepOutputFile)) 3954cc67fce91f43215d61b2695746eab102a3db516Stephen Hines return false; 3964cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 397c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines if (SuppressAllWarnings) { 398c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines getDiagnostics().setSuppressAllDiagnostics(true); 399c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines } 4004cc67fce91f43215d61b2695746eab102a3db516Stephen Hines if (generateDepFile() > 0) 4014cc67fce91f43215d61b2695746eab102a3db516Stephen Hines return false; 402c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines if (SuppressAllWarnings) { 403c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines getDiagnostics().setSuppressAllDiagnostics(false); 404c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines } 4054cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 4064cc67fce91f43215d61b2695746eab102a3db516Stephen Hines DepFileIter++; 4074cc67fce91f43215d61b2695746eab102a3db516Stephen Hines } 4084cc67fce91f43215d61b2695746eab102a3db516Stephen Hines 409e86245a09bb8b9e72f5dc68083444ec938865798Zonr Chang if (!checkODR(InputFile)) 410641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang return false; 411641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 412cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang IOFileIter++; 413cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang } 414cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang 415cf6af6abc1de499920571308b14a27e19cf57097Zonr Chang return true; 4163a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 4173a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang 418641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Changvoid SlangRS::reset() { 419641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete mRSContext; 420641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang mRSContext = NULL; 4214cc67fce91f43215d61b2695746eab102a3db516Stephen Hines mGeneratedFileNames.clear(); 422641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang Slang::reset(); 423641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang} 424641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang 4253a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr ChangSlangRS::~SlangRS() { 4263a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang delete mRSContext; 427641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 428641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang E = ReflectedDefinitions.end(); 429641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I != E; 430641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang I++) { 431641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang delete I->getValue().first; 432641558f02fe6ce0ee3ae5076eb366c25e2ad5903Zonr Chang } 4333a9ca1f0d6bd8f12c2bb2adea51f95c255996180Zonr Chang} 434e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines 435e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines} // namespace slang 436