diff --git a/frontend/src/common/prettier/plugins/clang/CustomFileSystem.cc b/frontend/src/common/prettier/plugins/clang/CustomFileSystem.cc new file mode 100644 index 0000000..8410289 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/CustomFileSystem.cc @@ -0,0 +1,117 @@ +#include "CustomFileSystem.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Path.h" +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::vfs; + +namespace { + +bool isRunningOnWindows() { + return EM_ASM_INT({return process.platform == 'win32' ? 1 : 0}) == 1; +} + +std::error_code current_path(SmallVectorImpl &result) { + result.clear(); + + const char *pwd = ::getenv("PWD"); + result.append(pwd, pwd + strlen(pwd)); + + return {}; +} + +} // namespace + +namespace llvm { +namespace vfs { + +sys::path::Style getPathStyle() { + static sys::path::Style cachedStyle = sys::path::Style::native; + + if (cachedStyle == sys::path::Style::native) { + cachedStyle = isRunningOnWindows() ? sys::path::Style::windows + : sys::path::Style::posix; + } + + return cachedStyle; +} + +void make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path) { + StringRef p(path.data(), path.size()); + + auto pathStyle = getPathStyle(); + + bool rootDirectory = sys::path::has_root_directory(p, pathStyle); + bool rootName = sys::path::has_root_name(p, pathStyle); + + // Already absolute. + if ((rootName || is_style_posix(pathStyle)) && rootDirectory) + return; + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + current_directory.toVector(current_dir); + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + sys::path::append(current_dir, pathStyle, p); + // Set path to the result. + path.swap(current_dir); + return; + } + + if (!rootName && rootDirectory) { + StringRef cdrn = sys::path::root_name(current_dir, pathStyle); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + sys::path::append(curDirRootName, pathStyle, p); + // Set path to the result. + path.swap(curDirRootName); + return; + } + + if (rootName && !rootDirectory) { + StringRef pRootName = sys::path::root_name(p, pathStyle); + StringRef bRootDirectory = + sys::path::root_directory(current_dir, pathStyle); + StringRef bRelativePath = sys::path::relative_path(current_dir, pathStyle); + StringRef pRelativePath = sys::path::relative_path(p, pathStyle); + + SmallString<128> res; + sys::path::append(res, pathStyle, pRootName, bRootDirectory, bRelativePath, + pRelativePath); + path.swap(res); + return; + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + +std::error_code make_absolute(SmallVectorImpl &path) { + if (sys::path::is_absolute(path, getPathStyle())) + return {}; + + SmallString<128> current_dir; + if (std::error_code ec = current_path(current_dir)) + return ec; + + make_absolute(current_dir, path); + return {}; +} + +CustomFileSystem::CustomFileSystem(IntrusiveRefCntPtr FS) + : ProxyFileSystem(std::move(FS)) {} + +std::error_code +CustomFileSystem::makeAbsolute(SmallVectorImpl &Path) const { + return make_absolute(Path); +} + +} // namespace vfs +} // namespace llvm diff --git a/frontend/src/common/prettier/plugins/clang/CustomFileSystem.h b/frontend/src/common/prettier/plugins/clang/CustomFileSystem.h new file mode 100644 index 0000000..1446382 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/CustomFileSystem.h @@ -0,0 +1,27 @@ +#ifndef CUSTOM_FILE_SYSTEM_H +#define CUSTOM_FILE_SYSTEM_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" + +namespace llvm { +namespace vfs { + +sys::path::Style getPathStyle(); +std::error_code make_absolute(SmallVectorImpl &path); + +class CustomFileSystem : public ProxyFileSystem { +public: + CustomFileSystem(IntrusiveRefCntPtr FS); + + std::error_code makeAbsolute(SmallVectorImpl &Path) const override; +}; + +} // namespace vfs +} // namespace llvm + +#endif // CUSTOM_FILE_SYSTEM_H diff --git a/frontend/src/common/prettier/plugins/clang/binding.cc b/frontend/src/common/prettier/plugins/clang/binding.cc new file mode 100644 index 0000000..92d4b88 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/binding.cc @@ -0,0 +1,26 @@ +#include "lib.h" +#include + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(my_module) { + register_vector("RangeList"); + + value_object("Result") + .field("error", &Result::error) + .field("content", &Result::content); + + function("version", &version); + function( + "format", &format); + function>("format_byte", &format_byte); + function>("format_line", &format_line); + function("set_fallback_style", &set_fallback_style); + function("set_sort_includes", &set_sort_includes); + function( + "dump_config", &dump_config); +} + +int main(void) {} diff --git a/frontend/src/common/prettier/plugins/clang/clang-format-cli.cjs b/frontend/src/common/prettier/plugins/clang/clang-format-cli.cjs new file mode 100644 index 0000000..2dddc9a --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format-cli.cjs @@ -0,0 +1,2 @@ +#!/usr/bin/env node +var Module=typeof Module!="undefined"?Module:{};var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=true;if(ENVIRONMENT_IS_NODE){}Module.preRun=function customPreRun(){ENV.PWD=process.cwd()};var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);var ret=fs.readFileSync(filename);return ret};readAsync=(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return new Promise((resolve,reject)=>{fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)reject(err);else resolve(binary?data.buffer:data)})})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);if(typeof module!="undefined"){module["exports"]=Module}quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="clang-format-cli.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["R"];updateMemoryViews();wasmTable=wasmExports["T"];addOnInit(wasmExports["S"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);return false}}wasmBinaryFile??=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult);return{}}var tempDouble;var tempI64;var ASM_CONSTS={1125e3:()=>process.platform=="win32"?1:0};class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var ___call_sighandler=(fp,sig)=>getWasmTableEntry(fp)(sig);class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var PATH={isAbs:path=>nodePath["isAbsolute"](path),normalize:path=>nodePath["normalize"](path),dirname:path=>nodePath["dirname"](path),basename:path=>nodePath["basename"](path),join:(...args)=>nodePath["join"](...args),join2:(l,r)=>nodePath["join"](l,r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...paths)=>{paths.unshift(FS.cwd());return nodePath["posix"]["resolve"](...paths)},relative:(from,to)=>nodePath["posix"]["relative"](from||FS.cwd(),to||FS.cwd())};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size)};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url).then(arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},err=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var NODEFS={isWindows:false,staticInit(){NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process.binding("constants");if(flags["fs"]){flags=flags["fs"]}NODEFS.flagsForNodeMap={1024:flags["O_APPEND"],64:flags["O_CREAT"],128:flags["O_EXCL"],256:flags["O_NOCTTY"],0:flags["O_RDONLY"],2:flags["O_RDWR"],4096:flags["O_SYNC"],512:flags["O_TRUNC"],1:flags["O_WRONLY"],131072:flags["O_NOFOLLOW"]}},convertNodeCode(e){var code=e.code;return ERRNO_CODES[code]},tryFSOperation(f){try{return f()}catch(e){if(!e.code)throw e;if(e.code==="UNKNOWN")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},mount(mount){return NODEFS.createNode(null,"/",NODEFS.getMode(mount.opts.root),0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode(path){var stat;return NODEFS.tryFSOperation(()=>{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode|=(stat.mode&292)>>2}return stat.mode})},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},flagsForNode(flags){flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;var newFlags=0;for(var k in NODEFS.flagsForNodeMap){if(flags&k){newFlags|=NODEFS.flagsForNodeMap[k];flags^=k}}if(flags){throw new FS.ErrnoError(28)}return newFlags},node_ops:{getattr(node){var path=NODEFS.realPath(node);var stat;NODEFS.tryFSOperation(()=>stat=fs.lstatSync(path));if(NODEFS.isWindows){if(!stat.blksize){stat.blksize=4096}if(!stat.blocks){stat.blocks=(stat.size+stat.blksize-1)/stat.blksize|0}stat.mode|=(stat.mode&292)>>2}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=NODEFS.realPath(node);NODEFS.tryFSOperation(()=>{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);fs.utimesSync(path,date,date)}if(attr.size!==undefined){fs.truncateSync(path,attr.size)}})},lookup(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod(parent,name,mode,dev){var node=NODEFS.createNode(parent,name,mode,dev);var path=NODEFS.realPath(node);NODEFS.tryFSOperation(()=>{if(FS.isDir(node.mode)){fs.mkdirSync(path,node.mode)}else{fs.writeFileSync(path,"",{mode:node.mode})}});return node},rename(oldNode,newDir,newName){var oldPath=NODEFS.realPath(oldNode);var newPath=PATH.join2(NODEFS.realPath(newDir),newName);NODEFS.tryFSOperation(()=>fs.renameSync(oldPath,newPath));oldNode.name=newName},unlink(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);NODEFS.tryFSOperation(()=>fs.unlinkSync(path))},rmdir(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);NODEFS.tryFSOperation(()=>fs.rmdirSync(path))},readdir(node){var path=NODEFS.realPath(node);return NODEFS.tryFSOperation(()=>fs.readdirSync(path))},symlink(parent,newName,oldPath){var newPath=PATH.join2(NODEFS.realPath(parent),newName);NODEFS.tryFSOperation(()=>fs.symlinkSync(oldPath,newPath))},readlink(node){var path=NODEFS.realPath(node);return NODEFS.tryFSOperation(()=>fs.readlinkSync(path))}},stream_ops:{open(stream){var path=NODEFS.realPath(stream.node);NODEFS.tryFSOperation(()=>{if(FS.isFile(stream.node.mode)){stream.shared.refcount=1;stream.nfd=fs.openSync(path,NODEFS.flagsForNode(stream.flags))}})},close(stream){NODEFS.tryFSOperation(()=>{if(FS.isFile(stream.node.mode)&&stream.nfd&&--stream.shared.refcount===0){fs.closeSync(stream.nfd)}})},dup(stream){stream.shared.refcount++},read(stream,buffer,offset,length,position){if(length===0)return 0;return NODEFS.tryFSOperation(()=>fs.readSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position))},write(stream,buffer,offset,length,position){return NODEFS.tryFSOperation(()=>fs.writeSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position))},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){NODEFS.tryFSOperation(()=>{var stat=fs.fstatSync(stream.nfd);position+=stat.size})}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}},msync(stream,buffer,offset,length,mmapFlags){NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var NODERAWFS={lookup(parent,name){return FS.lookupPath(`${parent.path}/${name}`).node},lookupPath(path,opts={}){if(opts.parent){path=nodePath.dirname(path)}var st=fs.lstatSync(path);var mode=NODEFS.getMode(path);return{path,node:{id:st.ino,mode,node_ops:NODERAWFS,path}}},createStandardStreams(){FS.createStream({nfd:0,position:0,path:"",flags:0,tty:true,seekable:false},0);for(var i=1;i<3;i++){FS.createStream({nfd:i,position:0,path:"",flags:577,tty:true,seekable:false},i)}},cwd(){return process.cwd()},chdir(...args){process.chdir(...args)},mknod(path,mode){if(FS.isDir(path)){fs.mkdirSync(path,mode)}else{fs.writeFileSync(path,"",{mode})}},mkdir(...args){fs.mkdirSync(...args)},symlink(...args){fs.symlinkSync(...args)},rename(...args){fs.renameSync(...args)},rmdir(...args){fs.rmdirSync(...args)},readdir(...args){return[".",".."].concat(fs.readdirSync(...args))},unlink(...args){fs.unlinkSync(...args)},readlink(...args){return fs.readlinkSync(...args)},stat(...args){return fs.statSync(...args)},lstat(...args){return fs.lstatSync(...args)},chmod(...args){fs.chmodSync(...args)},fchmod(fd,mode){var stream=FS.getStreamChecked(fd);fs.fchmodSync(stream.nfd,mode)},chown(...args){fs.chownSync(...args)},fchown(fd,owner,group){var stream=FS.getStreamChecked(fd);fs.fchownSync(stream.nfd,owner,group)},truncate(...args){fs.truncateSync(...args)},ftruncate(fd,len){if(len<0){throw new FS.ErrnoError(28)}var stream=FS.getStreamChecked(fd);fs.ftruncateSync(stream.nfd,len)},utime(path,atime,mtime){if(atime==-1||mtime==-1){var st=fs.statSync(path);if(atime==-1)atime=st.atimeMs;if(mtime==-1)mtime=st.mtimeMs}fs.utimesSync(path,atime/1e3,mtime/1e3)},open(path,flags,mode){if(typeof flags=="string"){flags=FS_modeStringToFlags(flags)}var pathTruncated=path.split("/").map(s=>s.substr(0,255)).join("/");var nfd=fs.openSync(pathTruncated,NODEFS.flagsForNode(flags),mode);var st=fs.fstatSync(nfd);if(flags&65536&&!st.isDirectory()){fs.closeSync(nfd);throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR)}var newMode=NODEFS.getMode(pathTruncated);var node={id:st.ino,mode:newMode,node_ops:NODERAWFS,path};return FS.createStream({nfd,position:0,path,flags,node,seekable:true})},createStream(stream,fd){var rtn=VFS.createStream(stream,fd);if(typeof rtn.shared.refcnt=="undefined"){rtn.shared.refcnt=1}else{rtn.shared.refcnt++}return rtn},close(stream){VFS.closeStream(stream.fd);if(!stream.stream_ops&&--stream.shared.refcnt===0){fs.closeSync(stream.nfd)}},llseek(stream,offset,whence){if(stream.stream_ops){return VFS.llseek(stream,offset,whence)}var position=offset;if(whence===1){position+=stream.position}else if(whence===2){position+=fs.fstatSync(stream.nfd).size}else if(whence!==0){throw new FS.ErrnoError(28)}if(position<0){throw new FS.ErrnoError(28)}stream.position=position;return position},read(stream,buffer,offset,length,position){if(stream.stream_ops){return VFS.read(stream,buffer,offset,length,position)}var seeking=typeof position!="undefined";if(!seeking&&stream.seekable)position=stream.position;var bytesRead=fs.readSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write(stream,buffer,offset,length,position){if(stream.stream_ops){return VFS.write(stream,buffer,offset,length,position)}if(stream.flags&+"1024"){FS.llseek(stream,0,+"2")}var seeking=typeof position!="undefined";if(!seeking&&stream.seekable)position=stream.position;var bytesWritten=fs.writeSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate(){throw new FS.ErrnoError(138)},mmap(stream,length,position,prot,flags){if(!length){throw new FS.ErrnoError(28)}if(stream.stream_ops){return VFS.mmap(stream,length,position,prot,flags)}var ptr=mmapAlloc(length);FS.read(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}},msync(stream,buffer,offset,length,mmapFlags){if(stream.stream_ops){return VFS.msync(stream,buffer,offset,length,mmapFlags)}FS.write(stream,buffer,0,length,offset);return 0},ioctl(){throw new FS.ErrnoError(59)}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},filesystems:null,syncFSRequests:0,readFiles:{},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS,NODEFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chdir(path){try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>>0,(tempDouble=id,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos>>2]=tempI64[0],HEAP32[dirp+pos+4>>2]=tempI64[1];tempI64=[(idx+1)*struct_size>>>0,(tempDouble=(idx+1)*struct_size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos+8>>2]=tempI64[0],HEAP32[dirp+pos+12>>2]=tempI64[1];HEAP16[dirp+pos+16>>1]=280;HEAP8[dirp+pos+18]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>2]=termios.c_iflag||0;HEAP32[argp+4>>2]=termios.c_oflag||0;HEAP32[argp+8>>2]=termios.c_cflag||0;HEAP32[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>2];var c_oflag=HEAP32[argp+4>>2];var c_cflag=HEAP32[argp+8>>2];var c_lflag=HEAP32[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>1]=winsize[0];HEAP16[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_readlinkat(dirfd,path,buf,bufsize){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_statfs64(path,size,buf){try{path=SYSCALLS.getStr(path);HEAP32[buf+4>>2]=4096;HEAP32[buf+40>>2]=4096;HEAP32[buf+8>>2]=1e6;HEAP32[buf+12>>2]=5e5;HEAP32[buf+16>>2]=5e5;HEAP32[buf+20>>2]=FS.nextInode;HEAP32[buf+24>>2]=1e6;HEAP32[buf+28>>2]=42;HEAP32[buf+44>>2]=2;HEAP32[buf+36>>2]=255;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>{abort("")};var nowIsMonotonic=1;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var runtimeKeepaliveCounter=0;var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function __gmtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var timers={};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var _emscripten_get_now=()=>performance.now();var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffset{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>2]:ch==105?HEAP32[buf>>2]:HEAPF64[buf>>3]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};var _emscripten_asm_const_int=(code,sigPtr,argbuf)=>runEmAsmFunction(code,sigPtr,argbuf);var _emscripten_date_now=()=>Date.now();var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack="";if(ENVIRONMENT_IS_NODE){NODEFS.staticInit()}if(!ENVIRONMENT_IS_NODE){throw new Error("NODERAWFS is currently only supported on Node.js environment.")}var _wrapNodeError=function(func){return function(...args){try{return func(...args)}catch(e){if(e.code){throw new FS.ErrnoError(ERRNO_CODES[e.code])}throw e}}};var VFS=Object.assign({},FS);for(var _key in NODERAWFS){FS[_key]=_wrapNodeError(NODERAWFS[_key])}var wasmImports={E:___call_sighandler,e:___cxa_throw,l:___syscall_chdir,m:___syscall_faccessat,j:___syscall_fcntl64,N:___syscall_fstat64,J:___syscall_getcwd,D:___syscall_getdents64,I:___syscall_ioctl,K:___syscall_lstat64,L:___syscall_newfstatat,i:___syscall_openat,C:___syscall_readlinkat,z:___syscall_renameat,A:___syscall_rmdir,M:___syscall_stat64,y:___syscall_statfs64,g:___syscall_unlinkat,n:__abort_js,O:__emscripten_get_now_is_monotonic,Q:__emscripten_memcpy_js,F:__emscripten_runtime_keepalive_clear,t:__gmtime_js,u:__localtime_js,q:__mmap_js,r:__munmap_js,f:__setitimer_js,G:__tzset_js,d:_emscripten_asm_const_int,P:_emscripten_date_now,x:_emscripten_get_heap_max,k:_emscripten_get_now,w:_emscripten_resize_heap,o:_environ_get,s:_environ_sizes_get,a:_exit,b:_fd_close,H:_fd_fdstat_get,p:_fd_pread,h:_fd_read,v:_fd_seek,c:_fd_write,B:_proc_exit};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["S"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["U"])(a0,a1);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["V"])(a0,a1);var __emscripten_timeout=(a0,a1)=>(__emscripten_timeout=wasmExports["W"])(a0,a1);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["X"])(a0);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>2]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>2]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run(); diff --git a/frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm b/frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm new file mode 100644 index 0000000..420771b Binary files /dev/null and b/frontend/src/common/prettier/plugins/clang/clang-format-cli.wasm differ diff --git a/frontend/src/common/prettier/plugins/clang/clang-format-diff.py b/frontend/src/common/prettier/plugins/clang/clang-format-diff.py new file mode 100644 index 0000000..3059982 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format-diff.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +# +# ===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===# +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===------------------------------------------------------------------------===# + +""" +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 --no-color --relative HEAD^ | {clang_format_diff} -p1 -i + svn diff --diff-cmd=diff -x-U0 | {clang_format_diff} -i + +It should be noted that the filename contained in the diff is used unmodified +to determine the source file to update. Users calling this script directly +should be careful to ensure that the path in the diff is correct relative to the +current working directory. +""" +from __future__ import absolute_import, division, print_function + +import argparse +import difflib +import re +import subprocess +import sys + +if sys.version_info.major >= 3: + from io import StringIO +else: + from io import BytesIO as StringIO + + +def main(): + parser = argparse.ArgumentParser( + description=__doc__.format(clang_format_diff="%(prog)s"), + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + "-i", + action="store_true", + default=False, + help="apply edits to files instead of displaying a diff", + ) + parser.add_argument( + "-p", + metavar="NUM", + default=0, + help="strip the smallest prefix containing P slashes", + ) + parser.add_argument( + "-regex", + metavar="PATTERN", + default=None, + help="custom pattern selecting file paths to reformat " + "(case sensitive, overrides -iregex)", + ) + parser.add_argument( + "-iregex", + metavar="PATTERN", + default=r".*\.(?:cpp|cc|c\+\+|cxx|cppm|ccm|cxxm|c\+\+m|c|cl|h|hh|hpp" + r"|hxx|m|mm|inc|js|ts|proto|protodevel|java|cs|json|ipynb|s?vh?)", + help="custom pattern selecting file paths to reformat " + "(case insensitive, overridden by -regex)", + ) + parser.add_argument( + "-sort-includes", + action="store_true", + default=False, + help="let clang-format sort include blocks", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="be more verbose, ineffective without -i", + ) + parser.add_argument( + "-style", + help="formatting style to apply (LLVM, GNU, Google, Chromium, " + "Microsoft, Mozilla, WebKit)", + ) + parser.add_argument( + "-fallback-style", + help="The name of the predefined style used as a" + "fallback in case clang-format is invoked with" + "-style=file, but can not find the .clang-format" + "file to use.", + ) + parser.add_argument( + "-binary", + default="clang-format", + help="location of binary to use for clang-format", + ) + args = parser.parse_args() + + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search(r"^\+\+\+\ (.*?/){%s}(.+)" % args.p, line.rstrip()) + if match: + filename = match.group(2) + if filename is None: + continue + + if args.regex is not None: + if not re.match("^%s$" % args.regex, filename): + continue + else: + if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE): + continue + + match = re.search(r"^@@.*\+(\d+)(?:,(\d+))?", line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(2): + line_count = int(match.group(2)) + # The input is something like + # + # @@ -1, +0,0 @@ + # + # which means no lines were added. + if line_count == 0: + continue + # Also format lines range if line_count is 0 in case of deleting + # surrounding statements. + end_line = start_line + if line_count != 0: + end_line += line_count - 1 + lines_by_file.setdefault(filename, []).extend( + ["--lines", str(start_line) + ":" + str(end_line)] + ) + + # Reformat files containing changes in place. + has_diff = False + for filename, lines in lines_by_file.items(): + if args.i and args.verbose: + print("Formatting {}".format(filename)) + command = [args.binary, filename] + if args.i: + command.append("-i") + if args.sort_includes: + command.append("--sort-includes") + command.extend(lines) + if args.style: + command.extend(["--style", args.style]) + if args.fallback_style: + command.extend(["--fallback-style", args.fallback_style]) + + try: + p = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True, + ) + except OSError as e: + # Give the user more context when clang-format isn't + # found/isn't executable, etc. + raise RuntimeError( + 'Failed to run "%s" - %s"' % (" ".join(command), e.strerror) + ) + + stdout, _stderr = p.communicate() + if p.returncode != 0: + return p.returncode + + if not args.i: + with open(filename) as f: + code = f.readlines() + formatted_code = StringIO(stdout).readlines() + diff = difflib.unified_diff( + code, + formatted_code, + filename, + filename, + "(before formatting)", + "(after formatting)", + ) + diff_string = "".join(diff) + if len(diff_string) > 0: + has_diff = True + sys.stdout.write(diff_string) + + if has_diff: + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/frontend/src/common/prettier/plugins/clang/clang-format-node.js b/frontend/src/common/prettier/plugins/clang/clang-format-node.js new file mode 100644 index 0000000..7f1dc96 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format-node.js @@ -0,0 +1,10 @@ +import fs from "node:fs/promises"; +import initAsync from "./clang-format.js"; + +const wasm = new URL("./clang-format.wasm", import.meta.url); + +export default function (init = fs.readFile(wasm)) { + return initAsync(init); +} + +export * from "./clang-format.js"; diff --git a/frontend/src/common/prettier/plugins/clang/clang-format-vite.js b/frontend/src/common/prettier/plugins/clang/clang-format-vite.js new file mode 100644 index 0000000..2b55cd1 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format-vite.js @@ -0,0 +1,8 @@ +import initAsync from "./clang-format.js"; +import wasm from "./clang-format.wasm?url"; + +export default function (input = wasm) { + return initAsync(input); +} + +export * from "./clang-format.js"; diff --git a/frontend/src/common/prettier/plugins/clang/clang-format.d.ts b/frontend/src/common/prettier/plugins/clang/clang-format.d.ts new file mode 100644 index 0000000..8feb94e --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format.d.ts @@ -0,0 +1,175 @@ +export type InitInput = + | RequestInfo + | URL + | Response + | BufferSource + | WebAssembly.Module; + +export default function init(input?: InitInput): Promise; + +/** + * The style to use for formatting. + * Supported style values are: + * - `LLVM` - A style complying with the LLVM coding standards. + * - `Google` - A style complying with Google’s C++ style guide. + * - `Chromium` - A style complying with Chromium’s style guide. + * - `Mozilla` - A style complying with Mozilla’s style guide. + * - `WebKit` - A style complying with WebKit’s style guide. + * - `Microsoft` - A style complying with Microsoft’s style guide. + * - `GNU` - A style complying with the GNU coding standards. + * - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`. + * - A string which represents `.clang-format` content. + * + */ +export type Style = + | "LLVM" + | "Google" + | "Chromium" + | "Mozilla" + | "WebKit" + | "Microsoft" + | "GNU" + | (string & {}); + +/** + * The filename to use for determining the language. + */ +export type Filename = + | "main.c" + | "main.cc" + | "main.cxx" + | "main.cpp" + | "main.java" + | "main.js" + | "main.mjs" + | "main.ts" + | "main.json" + | "main.m" + | "main.mm" + | "main.proto" + | "main.cs" + | (string & {}); + +/** + * Formats the given content using the specified style. + * + * @param {string} content - The content to format. + * @param {Filename} filename - The filename to use for determining the language. + * @param {Style} style - The style to use for formatting. + * Supported style values are: + * - `LLVM` - A style complying with the LLVM coding standards. + * - `Google` - A style complying with Google’s C++ style guide. + * - `Chromium` - A style complying with Chromium’s style guide. + * - `Mozilla` - A style complying with Mozilla’s style guide. + * - `WebKit` - A style complying with WebKit’s style guide. + * - `Microsoft` - A style complying with Microsoft’s style guide. + * - `GNU` - A style complying with the GNU coding standards. + * - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`. + * - A string which represents `.clang-format` content. + * + * @returns {string} The formatted content. + * @throws {Error} + * + * @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html} + */ +export declare function format( + content: string, + filename?: Filename, + style?: Style, +): string; + +/** + * Both the startLine and endLine are 1-based. + */ +export type LineRange = [startLine: number, endLine: number]; + +/** + * Both the offset and length are measured in bytes. + */ +export type ByteRange = [offset: number, length: number]; + +/** + * Formats the specified range of lines in the given content using the specified style. + * + * @param {string} content - The content to format. + * @param {LineRange[]} range - Array<[startLine, endLine]> - The range of lines to format. + * Both startLine and endLine are 1-based. + * Multiple ranges can be formatted by specifying several lines arguments. + * @param {Filename} filename - The filename to use for determining the language. + * @param {Style} style - The style to use for formatting. + * Supported style values are: + * - `LLVM` - A style complying with the LLVM coding standards. + * - `Google` - A style complying with Google’s C++ style guide. + * - `Chromium` - A style complying with Chromium’s style guide. + * - `Mozilla` - A style complying with Mozilla’s style guide. + * - `WebKit` - A style complying with WebKit’s style guide. + * - `Microsoft` - A style complying with Microsoft’s style guide. + * - `GNU` - A style complying with the GNU coding standards. + * - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`. + * - A string which represents `.clang-format` content. + * + * @returns {string} The formatted content. + * @throws {Error} + * + * @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html} + */ +export declare function format_line_range( + content: string, + range: ByteRange[] | [[offset: number]], + filename?: Filename, + style?: Style, +): string; + +/** + * @deprecated Use `format_line_range` instead. + */ +export declare function formatLineRange( + content: string, + range: ByteRange[] | [[offset: number]], + filename?: Filename, + style?: Style, +): string; + +/** + * Formats the specified range of bytes in the given content using the specified style. + * + * @param {string} content - The content to format. + * @param {ByteRange[]} range - Array<[offset, length]> - The range of bytes to format. + * @param {Filename} filename - The filename to use for determining the language. + * @param {Style} style - The style to use for formatting. + * Supported style values are: + * - `LLVM` - A style complying with the LLVM coding standards. + * - `Google` - A style complying with Google’s C++ style guide. + * - `Chromium` - A style complying with Chromium’s style guide. + * - `Mozilla` - A style complying with Mozilla’s style guide. + * - `WebKit` - A style complying with WebKit’s style guide. + * - `Microsoft` - A style complying with Microsoft’s style guide. + * - `GNU` - A style complying with the GNU coding standards. + * - A string starting with `{`, for example: `{BasedOnStyle: Chromium, IndentWidth: 4, ...}`. + * - A string which represents `.clang-format` content. + * + * @returns {string} The formatted content. + * @throws {Error} + * + * @see {@link https://clang.llvm.org/docs/ClangFormatStyleOptions.html} + */ +export declare function format_byte_range( + content: string, + range: LineRange[], + filename?: Filename, + style?: Style, +): string; + +/** + * @deprecated Use `format_byte_range` instead. + */ +export declare function formatByteRange( + content: string, + range: LineRange[], + filename?: Filename, + style?: Style, +): string; + +export declare function version(): string; + +export declare function set_fallback_style(style: Style): void; diff --git a/frontend/src/common/prettier/plugins/clang/clang-format.js b/frontend/src/common/prettier/plugins/clang/clang-format.js new file mode 100644 index 0000000..352d6d5 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/clang-format.js @@ -0,0 +1,155 @@ +/* @ts-self-types="./clang-format.d.ts" */ +async function load(module) { + if (typeof Response === "function" && module instanceof Response) { + if ("compileStreaming" in WebAssembly) { + try { + return await WebAssembly.compileStreaming(module); + } catch (e) { + if (module.headers.get("Content-Type") != "application/wasm") { + console.warn( + "`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", + e, + ); + } else { + throw e; + } + } + } + + return module.arrayBuffer(); + } + + return module; +} + +let wasm; +export default async function initAsync(input) { + if (wasm !== undefined) { + return wasm; + } + + if (typeof input === "undefined") { + input = new URL("clang-format.wasm", import.meta.url); + } + + if ( + typeof input === "string" || + (typeof Request === "function" && input instanceof Request) || + (typeof URL === "function" && input instanceof URL) + ) { + input = fetch(input); + } + + wasm = await load(await input).then((wasm) => Module({ wasm })); + assert_init = () => {}; +} + +function assert_init() { + throw new Error("uninit"); +} + +export function version() { + assert_init(); + return wasm.version(); +} + +export function set_fallback_style(style) { + assert_init(); + wasm.set_fallback_style(style); +} + +export function set_sort_includes(sort) { + assert_init(); + wasm.set_sort_includes(sort); +} + +function unwrap(result) { + const { error, content } = result; + if (error) { + throw Error(content); + } + return content; +} + +export function format(content, filename = "", style = "LLVM") { + assert_init(); + const result = wasm.format(content, filename, style); + return unwrap(result); +} + +export function format_line_range( + content, + range, + filename = "", + style = "LLVM", +) { + assert_init(); + const rangeList = new wasm.RangeList(); + for (const [fromLine, toLine] of range) { + if (fromLine < 1) { + throw Error("start line should be at least 1"); + } + if (fromLine > toLine) { + throw Error("start line should not exceed end line"); + } + rangeList.push_back(fromLine); + rangeList.push_back(toLine); + } + + const result = wasm.format_line(content, filename, style, rangeList); + rangeList.delete(); + return unwrap(result); +} + +export function format_byte_range( + content, + range, + filename = "", + style = "LLVM", +) { + assert_init(); + const rangeList = new wasm.RangeList(); + + if (range.length === 1 && range[0].length === 1) { + rangeList.push_back(range[0][0]); + } else { + for (const [offset, length] of range) { + if (offset < 0) { + throw Error("start offset should be at least 0"); + } + if (length < 0) { + throw Error("length should be at least 0"); + } + rangeList.push_back(offset); + rangeList.push_back(length); + } + } + + const result = wasm.format_byte(content, filename, style, rangeList); + rangeList.delete(); + return unwrap(result); +} + +export function dump_config({ + style = "file", + filename = "", + code = "", +} = {}) { + assert_init(); + const result = wasm.dump_config(style, filename, code); + return unwrap(result); +} + +export { + format_byte_range as formatByteRange, + format_line_range as formatLineRange, +}; +/** @nocollapse */ var Module = +function(moduleArg = {}) { + var moduleRtn; + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var out=text=>console.log(text);var err=text=>console.error(text);function ready(){readyPromiseResolve(Module);run()}function abort(what){throw what}var HEAP8,HEAP16,HEAP32,HEAPU8,HEAPU16,HEAPU32,HEAPF32,HEAPF64,wasmMemory;function updateMemoryViews(){var b=wasmMemory.buffer;HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b)}if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;wasmMemory=new WebAssembly.Memory({initial:INITIAL_MEMORY/65536,maximum:32768})}updateMemoryViews();var noExitRuntime=Module["noExitRuntime"]||true;var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var ___call_sighandler=(fp,sig)=>getWasmTableEntry(fp)(sig);class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var ___syscall_chdir=path=>{};var ___syscall_faccessat=(dirfd,path,amode,flags)=>{};var ___syscall_fstat64=(fd,buf)=>{};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var ___syscall_getcwd=(buf,size)=>{};var ___syscall_getdents64=(fd,dirp,count)=>{};var ___syscall_lstat64=(path,buf)=>{};var ___syscall_newfstatat=(dirfd,path,buf,flags)=>{};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var SYSCALLS={varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs}var ___syscall_readlinkat=(dirfd,path,buf,bufsize)=>{};var ___syscall_stat64=(path,buf)=>{};var ___syscall_statfs64=(path,size,buf)=>{};var ___syscall_unlinkat=(dirfd,path,flags)=>{};var __abort_js=()=>{abort("")};var structRegistrations={};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(type=>typeDependencies[type]=dependentTypes);function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};var __embind_finalize_value_object=structType=>{var reg=structRegistrations[structType];delete structRegistrations[structType];var rawConstructor=reg.rawConstructor;var rawDestructor=reg.rawDestructor;var fieldRecords=reg.fields;var fieldTypes=fieldRecords.map(field=>field.getterReturnType).concat(fieldRecords.map(field=>field.setterArgumentType));whenDependentTypesAreResolved([structType],fieldTypes,fieldTypes=>{var fields={};fieldRecords.forEach((field,i)=>{var fieldName=field.fieldName;var getterReturnType=fieldTypes[i];var getter=field.getter;var getterContext=field.getterContext;var setterArgumentType=fieldTypes[i+fieldRecords.length];var setter=field.setter;var setterContext=field.setterContext;fields[fieldName]={read:ptr=>getterReturnType["fromWireType"](getter(getterContext,ptr)),write:(ptr,o)=>{var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,o));runDestructors(destructors)}}});return[{name:reg.name,fromWireType:ptr=>{var rv={};for(var i in fields){rv[i]=fields[i].read(ptr)}rawDestructor(ptr);return rv},toWireType:(destructors,o)=>{for(var fieldName in fields){if(!(fieldName in o)){throw new TypeError(`Missing field: "${fieldName}"`)}}var ptr=rawConstructor();for(fieldName in fields){fields[fieldName].write(ptr,o[fieldName])}if(destructors!==null){destructors.push(rawDestructor,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:rawDestructor}]})};var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer])},destructorFunction:null})};var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var finalizationRegistry=false;var detachFinalizer=handle=>{};var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module[name].overloadTable.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCalls={};var dynCallLegacy=(sig,ptr,args)=>{sig=sig.replace(/p/g,"i");var f=dynCalls[sig];return f(ptr,...args)};var dynCall=(sig,ptr,args=[])=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr)(...args);return rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var __embind_register_class=(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor)=>{name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};function usesDestructorStack(argTypes){for(var i=1;i{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_function=(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync,isNonnullReturn)=>{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var emval_freelist=[];var emval_handles=[];var __emval_decref=handle=>{if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}};var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};var __embind_register_emval=rawType=>registerType(rawType,EmValType);var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync,isNonnullReturn)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer]:pointer=>HEAPU8[pointer];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name,fromWireType,toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})};var EmValOptionalType=Object.assign({optional:true},EmValType);var __embind_register_optional=(rawOptionalType,rawType)=>{registerType(rawOptionalType,EmValOptionalType)};var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name,fromWireType(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>1]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>2]}registerType(rawType,{name,fromWireType:value=>{var length=HEAPU32[value>>2];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_value_object=(rawType,name,constructorSignature,rawConstructor,destructorSignature,rawDestructor)=>{structRegistrations[rawType]={name:readLatin1String(name),rawConstructor:embind__requireFunction(constructorSignature,rawConstructor),rawDestructor:embind__requireFunction(destructorSignature,rawDestructor),fields:[]}};var __embind_register_value_object_field=(structType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext)=>{structRegistrations[structType].fields.push({fieldName:readLatin1String(fieldName),getterReturnType,getter:embind__requireFunction(getterSignature,getter),getterContext,setterArgumentType,setter:embind__requireFunction(setterSignature,setter),setterContext})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var __emval_take_value=(type,arg)=>{type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)};var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function __gmtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);return-52}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high)}var timers={};var callUserCallback=func=>func();var _emscripten_get_now=()=>performance.now();var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetDate.now();var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};var _proc_exit=code=>{throw`exit(${code})`};var _exit=_proc_exit;var _fd_close=fd=>52;var _fd_fdstat_get=(fd,pbuf)=>{var rightsBase=0;var rightsInheriting=0;var flags=0;{var type=2;if(fd==0){rightsBase=2}else if(fd==1||fd==2){rightsBase=64}flags=1}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0};function _fd_pread(fd,iov,iovcnt,offset_low,offset_high,pnum){var offset=convertI32PairToI53Checked(offset_low,offset_high);return 52}var _fd_read=(fd,iov,iovcnt,pnum)=>52;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);return 70}var printCharBuffers=[null,[],[]];var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer));buffer.length=0}else{buffer.push(curr)}};var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j>2]=num;return 0};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};init_ClassHandle();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var wasmImports={F:___call_sighandler,k:___cxa_throw,R:___syscall_chdir,S:___syscall_faccessat,O:___syscall_fstat64,K:___syscall_getcwd,D:___syscall_getdents64,L:___syscall_lstat64,M:___syscall_newfstatat,H:___syscall_openat,B:___syscall_readlinkat,N:___syscall_stat64,y:___syscall_statfs64,A:___syscall_unlinkat,T:__abort_js,W:__embind_finalize_value_object,u:__embind_register_bigint,_:__embind_register_bool,r:__embind_register_class,m:__embind_register_class_constructor,e:__embind_register_class_function,Z:__embind_register_emval,j:__embind_register_float,d:__embind_register_function,c:__embind_register_integer,b:__embind_register_memory_view,C:__embind_register_optional,i:__embind_register_std_string,f:__embind_register_std_wstring,aa:__embind_register_value_object,g:__embind_register_value_object_field,$:__embind_register_void,Q:__emscripten_memcpy_js,G:__emscripten_runtime_keepalive_clear,l:__emval_take_value,q:__gmtime_js,s:__localtime_js,o:__mmap_js,p:__munmap_js,z:__setitimer_js,I:__tzset_js,P:_emscripten_date_now,w:_emscripten_get_heap_max,v:_emscripten_resize_heap,U:_environ_get,V:_environ_sizes_get,Y:_exit,h:_fd_close,J:_fd_fdstat_get,n:_fd_pread,E:_fd_read,t:_fd_seek,x:_fd_write,a:wasmMemory,X:_proc_exit};function run(){var ret=_main()}function initRuntime(wasmExports){wasmExports["ba"]()}var _free,_malloc,_main,___getTypeName,__emscripten_timeout,_setThrew,__emscripten_tempret_set,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,dynCall_viiijii,dynCall_vij,dynCall_ji,dynCall_viiij,dynCall_viijii,dynCall_iiiiij,dynCall_iiiiijj,dynCall_iiiiiijj;var imports={a:wasmImports};WebAssembly.instantiate(Module["wasm"],imports).then(output=>{var wasmExports=(output.instance||output).exports;_free=wasmExports["da"];_malloc=wasmExports["ea"];_main=wasmExports["fa"];___getTypeName=wasmExports["ga"];__emscripten_timeout=wasmExports["ha"];_setThrew=wasmExports["ia"];__emscripten_tempret_set=wasmExports["ja"];__emscripten_stack_restore=wasmExports["ka"];__emscripten_stack_alloc=wasmExports["la"];_emscripten_stack_get_current=wasmExports["ma"];dynCall_viiijii=wasmExports["na"];dynCall_vij=wasmExports["oa"];dynCall_ji=wasmExports["pa"];dynCall_viiij=wasmExports["qa"];dynCall_viijii=wasmExports["ra"];dynCall_iiiiij=wasmExports["sa"];dynCall_iiiiijj=wasmExports["ta"];dynCall_iiiiiijj=wasmExports["ua"];wasmTable=wasmExports["ca"];initRuntime(wasmExports);ready()});moduleRtn=readyPromise; + + + return moduleRtn; +} diff --git a/frontend/src/common/prettier/plugins/clang/clang-format.wasm b/frontend/src/common/prettier/plugins/clang/clang-format.wasm new file mode 100644 index 0000000..3b77eee Binary files /dev/null and b/frontend/src/common/prettier/plugins/clang/clang-format.wasm differ diff --git a/frontend/src/common/prettier/plugins/clang/cli-pre.js b/frontend/src/common/prettier/plugins/clang/cli-pre.js new file mode 100644 index 0000000..d96a8dc --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/cli-pre.js @@ -0,0 +1,3 @@ +Module.preRun = function customPreRun() { + ENV.PWD = process.cwd(); +} diff --git a/frontend/src/common/prettier/plugins/clang/cli.cc b/frontend/src/common/prettier/plugins/clang/cli.cc new file mode 100644 index 0000000..5223f1d --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/cli.cc @@ -0,0 +1,748 @@ +//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a clang-format tool that automatically formats +/// (fragments of) C++ code. +/// +//===----------------------------------------------------------------------===// + +#include "clang/../../lib/Format/MatchFilePath.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Format/Format.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Process.h" +#include + +#include "CustomFileSystem.h" + +using namespace llvm; +using clang::tooling::Replacements; + +static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); + +// Mark all our options with this category, everything else (except for -version +// and -help) will be hidden. +static cl::OptionCategory ClangFormatCategory("Clang-format options"); + +static cl::list + Offsets("offset", + cl::desc("Format a range starting at this byte offset.\n" + "Multiple ranges can be formatted by specifying\n" + "several -offset and -length pairs.\n" + "Can only be used with one input file."), + cl::cat(ClangFormatCategory)); +static cl::list + Lengths("length", + cl::desc("Format a range of this length (in bytes).\n" + "Multiple ranges can be formatted by specifying\n" + "several -offset and -length pairs.\n" + "When only a single -offset is specified without\n" + "-length, clang-format will format up to the end\n" + "of the file.\n" + "Can only be used with one input file."), + cl::cat(ClangFormatCategory)); +static cl::list + LineRanges("lines", + cl::desc(": - format a range of\n" + "lines (both 1-based).\n" + "Multiple ranges can be formatted by specifying\n" + "several -lines arguments.\n" + "Can't be used with -offset and -length.\n" + "Can only be used with one input file."), + cl::cat(ClangFormatCategory)); +static cl::opt + Style("style", cl::desc(clang::format::StyleOptionHelpDescription), + cl::init(clang::format::DefaultFormatStyle), + cl::cat(ClangFormatCategory)); +static cl::opt + FallbackStyle("fallback-style", + cl::desc("The name of the predefined style used as a\n" + "fallback in case clang-format is invoked with\n" + "-style=file, but can not find the .clang-format\n" + "file to use. Defaults to 'LLVM'.\n" + "Use -fallback-style=none to skip formatting."), + cl::init(clang::format::DefaultFallbackStyle), + cl::cat(ClangFormatCategory)); + +static cl::opt AssumeFileName( + "assume-filename", + cl::desc("Set filename used to determine the language and to find\n" + ".clang-format file.\n" + "Only used when reading from stdin.\n" + "If this is not passed, the .clang-format file is searched\n" + "relative to the current working directory when reading stdin.\n" + "Unrecognized filenames are treated as C++.\n" + "supported:\n" + " CSharp: .cs\n" + " Java: .java\n" + " JavaScript: .js .mjs .cjs .ts\n" + " Json: .json .ipynb\n" + " Objective-C: .m .mm\n" + " Proto: .proto .protodevel\n" + " TableGen: .td\n" + " TextProto: .txtpb .textpb .pb.txt .textproto .asciipb\n" + " Verilog: .sv .svh .v .vh"), + cl::init(""), cl::cat(ClangFormatCategory)); + +static cl::opt Inplace("i", + cl::desc("Inplace edit s, if specified."), + cl::cat(ClangFormatCategory)); + +static cl::opt OutputXML("output-replacements-xml", + cl::desc("Output replacements as XML."), + cl::cat(ClangFormatCategory)); +static cl::opt + DumpConfig("dump-config", + cl::desc("Dump configuration options to stdout and exit.\n" + "Can be used with -style option."), + cl::cat(ClangFormatCategory)); +static cl::opt + Cursor("cursor", + cl::desc("The position of the cursor when invoking\n" + "clang-format from an editor integration"), + cl::init(0), cl::cat(ClangFormatCategory)); + +static cl::opt + SortIncludes("sort-includes", + cl::desc("If set, overrides the include sorting behavior\n" + "determined by the SortIncludes style flag"), + cl::cat(ClangFormatCategory)); + +static cl::opt QualifierAlignment( + "qualifier-alignment", + cl::desc("If set, overrides the qualifier alignment style\n" + "determined by the QualifierAlignment style flag"), + cl::init(""), cl::cat(ClangFormatCategory)); + +static cl::opt Files( + "files", + cl::desc("A file containing a list of files to process, one per line."), + cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory)); + +static cl::opt + Verbose("verbose", cl::desc("If set, shows the list of processed files"), + cl::cat(ClangFormatCategory)); + +// Use --dry-run to match other LLVM tools when you mean do it but don't +// actually do it +static cl::opt + DryRun("dry-run", + cl::desc("If set, do not actually make the formatting changes"), + cl::cat(ClangFormatCategory)); + +// Use -n as a common command as an alias for --dry-run. (git and make use -n) +static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"), + cl::cat(ClangFormatCategory), cl::aliasopt(DryRun), + cl::NotHidden); + +// Emulate being able to turn on/off the warning. +static cl::opt + WarnFormat("Wclang-format-violations", + cl::desc("Warnings about individual formatting changes needed. " + "Used only with --dry-run or -n"), + cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt + NoWarnFormat("Wno-clang-format-violations", + cl::desc("Do not warn about individual formatting changes " + "needed. Used only with --dry-run or -n"), + cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt ErrorLimit( + "ferror-limit", + cl::desc("Set the maximum number of clang-format errors to emit\n" + "before stopping (0 = no limit).\n" + "Used only with --dry-run or -n"), + cl::init(0), cl::cat(ClangFormatCategory)); + +static cl::opt + WarningsAsErrors("Werror", + cl::desc("If set, changes formatting warnings to errors"), + cl::cat(ClangFormatCategory)); + +namespace { +enum class WNoError { Unknown }; +} + +static cl::bits WNoErrorList( + "Wno-error", + cl::desc("If set, don't error out on the specified warning type."), + cl::values( + clEnumValN(WNoError::Unknown, "unknown", + "If set, unknown format options are only warned about.\n" + "This can be used to enable formatting, even if the\n" + "configuration contains unknown (newer) options.\n" + "Use with caution, as this might lead to dramatically\n" + "differing format depending on an option being\n" + "supported or not.")), + cl::cat(ClangFormatCategory)); + +static cl::opt + ShowColors("fcolor-diagnostics", + cl::desc("If set, and on a color-capable terminal controls " + "whether or not to print diagnostics in color"), + cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt + NoShowColors("fno-color-diagnostics", + cl::desc("If set, and on a color-capable terminal controls " + "whether or not to print diagnostics in color"), + cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::list FileNames(cl::Positional, + cl::desc("[@] [ ...]"), + cl::cat(ClangFormatCategory)); + +static cl::opt FailOnIncompleteFormat( + "fail-on-incomplete-format", + cl::desc("If set, fail with exit code 1 on incomplete format."), + cl::init(false), cl::cat(ClangFormatCategory)); + +static cl::opt ListIgnored("list-ignored", + cl::desc("List ignored files."), + cl::cat(ClangFormatCategory), cl::Hidden); + +namespace clang { +namespace format { + +static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source, + SourceManager &Sources, FileManager &Files, + llvm::vfs::InMemoryFileSystem *MemFS) { + MemFS->addFileNoOwn(FileName, 0, Source); + auto File = Files.getOptionalFileRef(FileName); + assert(File && "File not added to MemFS?"); + return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User); +} + +// Parses : input to a pair of line numbers. +// Returns true on error. +static bool parseLineRange(StringRef Input, unsigned &FromLine, + unsigned &ToLine) { + std::pair LineRange = Input.split(':'); + return LineRange.first.getAsInteger(0, FromLine) || + LineRange.second.getAsInteger(0, ToLine); +} + +static bool fillRanges(MemoryBuffer *Code, + std::vector &Ranges) { + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts); + SourceManager Sources(Diagnostics, Files); + const auto ID = createInMemoryFile("", *Code, Sources, Files, + InMemoryFileSystem.get()); + if (!LineRanges.empty()) { + if (!Offsets.empty() || !Lengths.empty()) { + errs() << "error: cannot use -lines with -offset/-length\n"; + return true; + } + + for (const auto &LineRange : LineRanges) { + unsigned FromLine, ToLine; + if (parseLineRange(LineRange, FromLine, ToLine)) { + errs() << "error: invalid : pair\n"; + return true; + } + if (FromLine < 1) { + errs() << "error: start line should be at least 1\n"; + return true; + } + if (FromLine > ToLine) { + errs() << "error: start line should not exceed end line\n"; + return true; + } + const auto Start = Sources.translateLineCol(ID, FromLine, 1); + const auto End = Sources.translateLineCol(ID, ToLine, UINT_MAX); + if (Start.isInvalid() || End.isInvalid()) + return true; + const auto Offset = Sources.getFileOffset(Start); + const auto Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); + } + return false; + } + + if (Offsets.empty()) + Offsets.push_back(0); + const bool EmptyLengths = Lengths.empty(); + unsigned Length = 0; + if (Offsets.size() == 1 && EmptyLengths) { + Length = Sources.getFileOffset(Sources.getLocForEndOfFile(ID)) - Offsets[0]; + } else if (Offsets.size() != Lengths.size()) { + errs() << "error: number of -offset and -length arguments must match.\n"; + return true; + } + for (unsigned I = 0, E = Offsets.size(), CodeSize = Code->getBufferSize(); + I < E; ++I) { + const auto Offset = Offsets[I]; + if (Offset >= CodeSize) { + errs() << "error: offset " << Offset << " is outside the file\n"; + return true; + } + if (!EmptyLengths) + Length = Lengths[I]; + if (Offset + Length > CodeSize) { + errs() << "error: invalid length " << Length << ", offset + length (" + << Offset + Length << ") is outside the file.\n"; + return true; + } + Ranges.push_back(tooling::Range(Offset, Length)); + } + return false; +} + +static void outputReplacementXML(StringRef Text) { + // FIXME: When we sort includes, we need to make sure the stream is correct + // utf-8. + size_t From = 0; + size_t Index; + while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) { + outs() << Text.substr(From, Index - From); + switch (Text[Index]) { + case '\n': + outs() << " "; + break; + case '\r': + outs() << " "; + break; + case '<': + outs() << "<"; + break; + case '&': + outs() << "&"; + break; + default: + llvm_unreachable("Unexpected character encountered!"); + } + From = Index + 1; + } + outs() << Text.substr(From); +} + +static void outputReplacementsXML(const Replacements &Replaces) { + for (const auto &R : Replaces) { + outs() << ""; + outputReplacementXML(R.getReplacementText()); + outs() << "\n"; + } +} + +static bool +emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName, + const std::unique_ptr &Code) { + unsigned Errors = 0; + if (WarnFormat && !NoWarnFormat) { + SourceMgr Mgr; + const char *StartBuf = Code->getBufferStart(); + + Mgr.AddNewSourceBuffer( + MemoryBuffer::getMemBuffer(StartBuf, AssumedFileName), SMLoc()); + for (const auto &R : Replaces) { + SMDiagnostic Diag = Mgr.GetMessage( + SMLoc::getFromPointer(StartBuf + R.getOffset()), + WarningsAsErrors ? SourceMgr::DiagKind::DK_Error + : SourceMgr::DiagKind::DK_Warning, + "code should be clang-formatted [-Wclang-format-violations]"); + + Diag.print(nullptr, llvm::errs(), ShowColors && !NoShowColors); + if (ErrorLimit && ++Errors >= ErrorLimit) + break; + } + } + return WarningsAsErrors; +} + +static void outputXML(const Replacements &Replaces, + const Replacements &FormatChanges, + const FormattingAttemptStatus &Status, + const cl::opt &Cursor, + unsigned CursorPosition) { + outs() << "\n\n"; + if (Cursor.getNumOccurrences() != 0) { + outs() << "" << FormatChanges.getShiftedCodePosition(CursorPosition) + << "\n"; + } + + outputReplacementsXML(Replaces); + outs() << "\n"; +} + +class ClangFormatDiagConsumer : public DiagnosticConsumer { + virtual void anchor() {} + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + + SmallVector vec; + Info.FormatDiagnostic(vec); + errs() << "clang-format error:" << vec << "\n"; + } +}; + +// Returns true on error. +static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { + const bool IsSTDIN = FileName == "-"; + if (!OutputXML && Inplace && IsSTDIN) { + errs() << "error: cannot use -i when reading from stdin.\n"; + return true; + } + // On Windows, overwriting a file with an open file mapping doesn't work, + // so read the whole file into memory when formatting in-place. + ErrorOr> CodeOrErr = + !OutputXML && Inplace + ? MemoryBuffer::getFileAsStream(FileName) + : MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/true); + if (std::error_code EC = CodeOrErr.getError()) { + errs() << FileName << ": " << EC.message() << "\n"; + return true; + } + std::unique_ptr Code = std::move(CodeOrErr.get()); + if (Code->getBufferSize() == 0) + return false; // Empty files are formatted correctly. + + StringRef BufStr = Code->getBuffer(); + + const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr); + + if (InvalidBOM) { + errs() << "error: encoding with unsupported byte order mark \"" + << InvalidBOM << "\" detected"; + if (!IsSTDIN) + errs() << " in file '" << FileName << "'"; + errs() << ".\n"; + return true; + } + + std::vector Ranges; + if (fillRanges(Code.get(), Ranges)) + return true; + StringRef AssumedFileName = IsSTDIN ? AssumeFileName : FileName; + if (AssumedFileName.empty()) { + llvm::errs() << "error: empty filenames are not allowed\n"; + return true; + } + + auto RealFS = vfs::getRealFileSystem(); + auto CustomFS = new vfs::CustomFileSystem(RealFS); + IntrusiveRefCntPtr CustomFSPtr(CustomFS); + Expected FormatStyle = + getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(), + CustomFSPtr.get(), WNoErrorList.isSet(WNoError::Unknown)); + if (!FormatStyle) { + llvm::errs() << toString(FormatStyle.takeError()) << "\n"; + return true; + } + + StringRef QualifierAlignmentOrder = QualifierAlignment; + + FormatStyle->QualifierAlignment = + StringSwitch( + QualifierAlignmentOrder.lower()) + .Case("right", FormatStyle::QAS_Right) + .Case("left", FormatStyle::QAS_Left) + .Default(FormatStyle->QualifierAlignment); + + if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) { + FormatStyle->QualifierOrder = {"const", "volatile", "type"}; + } else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) { + FormatStyle->QualifierOrder = {"type", "const", "volatile"}; + } else if (QualifierAlignmentOrder.contains("type")) { + FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom; + SmallVector Qualifiers; + QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()}; + } + + if (SortIncludes.getNumOccurrences() != 0) { + FormatStyle->SortIncludes = {}; + if (SortIncludes) + FormatStyle->SortIncludes.Enabled = true; + } + unsigned CursorPosition = Cursor; + Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges, + AssumedFileName, &CursorPosition); + + const bool IsJson = FormatStyle->isJson(); + + // To format JSON insert a variable to trick the code into thinking its + // JavaScript. + if (IsJson && !FormatStyle->DisableFormat) { + auto Err = + Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = ")); + if (Err) + llvm::errs() << "Bad Json variable insertion\n"; + } + + auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); + if (!ChangedCode) { + llvm::errs() << toString(ChangedCode.takeError()) << "\n"; + return true; + } + // Get new affected ranges after sorting `#includes`. + Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); + FormattingAttemptStatus Status; + Replacements FormatChanges = + reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replaces = Replaces.merge(FormatChanges); + if (DryRun) { + return Replaces.size() > (IsJson ? 1u : 0u) && + emitReplacementWarnings(Replaces, AssumedFileName, Code); + } + if (OutputXML) { + outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition); + } else { + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + + DiagnosticOptions DiagOpts; + ClangFormatDiagConsumer IgnoreDiagnostics; + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts, + &IgnoreDiagnostics, false); + SourceManager Sources(Diagnostics, Files); + FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files, + InMemoryFileSystem.get()); + Rewriter Rewrite(Sources, LangOptions()); + tooling::applyAllReplacements(Replaces, Rewrite); + if (Inplace) { + if (Rewrite.overwriteChangedFiles()) + return true; + } else { + if (Cursor.getNumOccurrences() != 0) { + outs() << "{ \"Cursor\": " + << FormatChanges.getShiftedCodePosition(CursorPosition) + << ", \"IncompleteFormat\": " + << (Status.FormatComplete ? "false" : "true"); + if (!Status.FormatComplete) + outs() << ", \"Line\": " << Status.Line; + outs() << " }\n"; + } + Rewrite.getEditBuffer(ID).write(outs()); + } + } + return ErrorOnIncompleteFormat && !Status.FormatComplete; +} + +} // namespace format +} // namespace clang + +static void PrintVersion(raw_ostream &OS) { + OS << clang::getClangToolFullVersion("clang-format") << '\n'; +} + +// Dump the configuration. +static int dumpConfig() { + std::unique_ptr Code; + // We can't read the code to detect the language if there's no file name. + if (!FileNames.empty()) { + // Read in the code in case the filename alone isn't enough to detect the + // language. + ErrorOr> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(FileNames[0], /*IsText=*/true); + if (std::error_code EC = CodeOrErr.getError()) { + llvm::errs() << EC.message() << "\n"; + return 1; + } + Code = std::move(CodeOrErr.get()); + } + + auto RealFS = vfs::getRealFileSystem(); + auto CustomFS = new vfs::CustomFileSystem(RealFS); + IntrusiveRefCntPtr CustomFSPtr(CustomFS); + + Expected FormatStyle = clang::format::getStyle( + Style, + FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0], + FallbackStyle, Code ? Code->getBuffer() : "", CustomFSPtr.get()); + if (!FormatStyle) { + llvm::errs() << toString(FormatStyle.takeError()) << "\n"; + return 1; + } + std::string Config = clang::format::configurationAsText(*FormatStyle); + outs() << Config << "\n"; + return 0; +} + +using String = SmallString<128>; +static String IgnoreDir; // Directory of .clang-format-ignore file. +static String PrevDir; // Directory of previous `FilePath`. +static SmallVector Patterns; // Patterns in .clang-format-ignore file. + +// Check whether `FilePath` is ignored according to the nearest +// .clang-format-ignore file based on the rules below: +// - A blank line is skipped. +// - Leading and trailing spaces of a line are trimmed. +// - A line starting with a hash (`#`) is a comment. +// - A non-comment line is a single pattern. +// - The slash (`/`) is used as the directory separator. +// - A pattern is relative to the directory of the .clang-format-ignore file (or +// the root directory if the pattern starts with a slash). +// - A pattern is negated if it starts with a bang (`!`). +static bool isIgnored(StringRef FilePath) { + using namespace llvm::sys::fs; + if (!is_regular_file(FilePath)) + return false; + + String Path; + String AbsPath{FilePath}; + + auto PathStyle = vfs::getPathStyle(); + + using namespace llvm::sys::path; + vfs::make_absolute(AbsPath); + remove_dots(AbsPath, /*remove_dot_dot=*/true, PathStyle); + + if (StringRef Dir{parent_path(AbsPath, PathStyle)}; PrevDir != Dir) { + PrevDir = Dir; + + for (;;) { + Path = Dir; + append(Path, PathStyle, ".clang-format-ignore"); + if (is_regular_file(Path)) + break; + Dir = parent_path(Dir, PathStyle); + if (Dir.empty()) + return false; + } + + IgnoreDir = convert_to_slash(Dir, PathStyle); + + std::ifstream IgnoreFile{Path.c_str()}; + if (!IgnoreFile.good()) + return false; + + Patterns.clear(); + + for (std::string Line; std::getline(IgnoreFile, Line);) { + if (const auto Pattern{StringRef{Line}.trim()}; + // Skip empty and comment lines. + !Pattern.empty() && Pattern[0] != '#') { + Patterns.push_back(Pattern); + } + } + } + + if (IgnoreDir.empty()) + return false; + + const auto Pathname{convert_to_slash(AbsPath, PathStyle)}; + for (const auto &Pat : Patterns) { + const bool IsNegated = Pat[0] == '!'; + StringRef Pattern{Pat}; + if (IsNegated) + Pattern = Pattern.drop_front(); + + if (Pattern.empty()) + continue; + + Pattern = Pattern.ltrim(); + + // `Pattern` is relative to `IgnoreDir` unless it starts with a slash. + // This doesn't support patterns containing drive names (e.g. `C:`). + if (Pattern[0] != '/') { + Path = IgnoreDir; + append(Path, Style::posix, Pattern); + remove_dots(Path, /*remove_dot_dot=*/true, Style::posix); + Pattern = Path; + } + + if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated) + return true; + } + + return false; +} + +int main(int argc, const char **argv) { + InitLLVM X(argc, argv); + + cl::HideUnrelatedOptions(ClangFormatCategory); + + cl::SetVersionPrinter(PrintVersion); + cl::ParseCommandLineOptions( + argc, argv, + "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# " + "code.\n\n" + "If no arguments are specified, it formats the code from standard input\n" + "and writes the result to the standard output.\n" + "If s are given, it reformats the files. If -i is specified\n" + "together with s, the files are edited in-place. Otherwise, the\n" + "result is written to the standard output.\n"); + + if (Help) { + cl::PrintHelpMessage(); + return 0; + } + + if (DumpConfig) + return dumpConfig(); + + if (!Files.empty()) { + std::ifstream ExternalFileOfFiles{std::string(Files)}; + std::string Line; + unsigned LineNo = 1; + while (std::getline(ExternalFileOfFiles, Line)) { + FileNames.push_back(Line); + LineNo++; + } + errs() << "Clang-formatting " << LineNo << " files\n"; + } + + if (FileNames.empty()) { + if (isIgnored(AssumeFileName)) + return 0; + return clang::format::format("-", FailOnIncompleteFormat); + } + + if (FileNames.size() > 1 && + (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { + errs() << "error: -offset, -length and -lines can only be used for " + "single file.\n"; + return 1; + } + + unsigned FileNo = 1; + bool Error = false; + for (const auto &FileName : FileNames) { + const bool Ignored = isIgnored(FileName); + if (ListIgnored) { + if (Ignored) + outs() << FileName << '\n'; + continue; + } + if (Ignored) + continue; + if (Verbose) { + errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] " + << FileName << "\n"; + } + Error |= clang::format::format(FileName, FailOnIncompleteFormat); + } + return Error ? 1 : 0; +} diff --git a/frontend/src/common/prettier/plugins/clang/git-clang-format b/frontend/src/common/prettier/plugins/clang/git-clang-format new file mode 100644 index 0000000..e709803 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/git-clang-format @@ -0,0 +1,858 @@ +#!/usr/bin/env python3 +# +# ===- git-clang-format - ClangFormat Git Integration -------*- python -*--=== # +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------=== # + +r""" +clang-format git integration +============================ + +This file provides a clang-format integration for git. Put it somewhere in your +path and ensure that it is executable. Then, "git clang-format" will invoke +clang-format on the changes in current files or a specific commit. + +For further details, run: +git clang-format -h + +Requires Python version >=3.8 +""" + +from __future__ import absolute_import, division, print_function +import argparse +import collections +import contextlib +import errno +import os +import re +import subprocess +import sys + +usage = "git clang-format [OPTIONS] [] [|--staged] [--] [...]" + +desc = """ +If zero or one commits are given, run clang-format on all lines that differ +between the working directory and , which defaults to HEAD. Changes are +only applied to the working directory, or in the stage/index. + +Examples: + To format staged changes, i.e everything that's been `git add`ed: + git clang-format + + To also format everything touched in the most recent commit: + git clang-format HEAD~1 + + If you're on a branch off main, to format everything touched on your branch: + git clang-format main + +If two commits are given (requires --diff), run clang-format on all lines in the +second that differ from the first . + +The following git-config settings set the default of the corresponding option: + clangFormat.binary + clangFormat.commit + clangFormat.extensions + clangFormat.style +""" + +# Name of the temporary index file in which save the output of clang-format. +# This file is created within the .git directory. +temp_index_basename = "clang-format-index" + + +Range = collections.namedtuple("Range", "start, count") + + +def main(): + config = load_git_config() + + # In order to keep '--' yet allow options after positionals, we need to + # check for '--' ourselves. (Setting nargs='*' throws away the '--', while + # nargs=argparse.REMAINDER disallows options after positionals.) + argv = sys.argv[1:] + try: + idx = argv.index("--") + except ValueError: + dash_dash = [] + else: + dash_dash = argv[idx:] + argv = argv[:idx] + + default_extensions = ",".join( + [ + # From clang/lib/Frontend/FrontendOptions.cpp, all lower case + "c", + "h", # C + "m", # ObjC + "mm", # ObjC++ + "cc", + "cp", + "cpp", + "c++", + "cxx", + "hh", + "hpp", + "hxx", + "inc", # C++ + "ccm", + "cppm", + "cxxm", + "c++m", # C++ Modules + "cu", + "cuh", # CUDA + "cl", # OpenCL + # Other languages that clang-format supports + "proto", + "protodevel", # Protocol Buffers + "java", # Java + "js", + "mjs", + "cjs", # JavaScript + "ts", # TypeScript + "cs", # C Sharp + "json", + "ipynb", # Json + "sv", + "svh", + "v", + "vh", # Verilog + "td", # TableGen + "txtpb", + "textpb", + "pb.txt", + "textproto", + "asciipb", # TextProto + ] + ) + + p = argparse.ArgumentParser( + usage=usage, + formatter_class=argparse.RawDescriptionHelpFormatter, + description=desc, + ) + p.add_argument( + "--binary", + default=config.get("clangformat.binary", "clang-format"), + help="path to clang-format", + ), + p.add_argument( + "--commit", + default=config.get("clangformat.commit", "HEAD"), + help="default commit to use if none is specified", + ), + p.add_argument( + "--diff", + action="store_true", + help="print a diff instead of applying the changes", + ) + p.add_argument( + "--diffstat", + action="store_true", + help="print a diffstat instead of applying the changes", + ) + p.add_argument( + "--extensions", + default=config.get("clangformat.extensions", default_extensions), + help=( + "comma-separated list of file extensions to format, " + "excluding the period and case-insensitive" + ), + ), + p.add_argument( + "-f", + "--force", + action="store_true", + help="allow changes to unstaged files", + ) + p.add_argument( + "-p", "--patch", action="store_true", help="select hunks interactively" + ) + p.add_argument( + "-q", + "--quiet", + action="count", + default=0, + help="print less information", + ) + p.add_argument( + "--staged", + "--cached", + action="store_true", + help="format lines in the stage instead of the working dir", + ) + p.add_argument( + "--style", + default=config.get("clangformat.style", None), + help="passed to clang-format", + ), + p.add_argument( + "-v", + "--verbose", + action="count", + default=0, + help="print extra information", + ) + p.add_argument( + "--diff_from_common_commit", + action="store_true", + help=( + "diff from the last common commit for commits in " + "separate branches rather than the exact point of the " + "commits" + ), + ) + # We gather all the remaining positional arguments into 'args' since we need + # to use some heuristics to determine whether or not was present. + # However, to print pretty messages, we make use of metavar and help. + p.add_argument( + "args", + nargs="*", + metavar="", + help="revision from which to compute the diff", + ) + p.add_argument( + "ignored", + nargs="*", + metavar="...", + help="if specified, only consider differences in these files", + ) + opts = p.parse_args(argv) + + opts.verbose -= opts.quiet + del opts.quiet + + commits, files = interpret_args(opts.args, dash_dash, opts.commit) + if len(commits) > 2: + die("at most two commits allowed; %d given" % len(commits)) + if len(commits) == 2: + if opts.staged: + die("--staged is not allowed when two commits are given") + if not opts.diff: + die("--diff is required when two commits are given") + elif opts.diff_from_common_commit: + die("--diff_from_common_commit is only allowed when two commits are given") + + if os.path.dirname(opts.binary): + opts.binary = os.path.abspath(opts.binary) + + changed_lines = compute_diff_and_extract_lines( + commits, files, opts.staged, opts.diff_from_common_commit + ) + if opts.verbose >= 1: + ignored_files = set(changed_lines) + filter_by_extension(changed_lines, opts.extensions.lower().split(",")) + # The computed diff outputs absolute paths, so we must cd before accessing + # those files. + cd_to_toplevel() + filter_symlinks(changed_lines) + filter_ignored_files(changed_lines, binary=opts.binary) + if opts.verbose >= 1: + ignored_files.difference_update(changed_lines) + if ignored_files: + print( + "Ignoring the following files (wrong extension, symlink, or " + "ignored by clang-format):" + ) + for filename in ignored_files: + print(" %s" % filename) + if changed_lines: + print("Running clang-format on the following files:") + for filename in changed_lines: + print(" %s" % filename) + + if not changed_lines: + if opts.verbose >= 0: + print("no modified files to format") + return 0 + + if len(commits) > 1: + old_tree = commits[1] + revision = old_tree + elif opts.staged: + old_tree = create_tree_from_index(changed_lines) + revision = "" + else: + old_tree = create_tree_from_workdir(changed_lines) + revision = None + new_tree = run_clang_format_and_save_to_tree( + changed_lines, revision, binary=opts.binary, style=opts.style + ) + if opts.verbose >= 1: + print("old tree: %s" % old_tree) + print("new tree: %s" % new_tree) + + if old_tree == new_tree: + if opts.verbose >= 0: + print("clang-format did not modify any files") + return 0 + + if opts.diff: + return print_diff(old_tree, new_tree) + if opts.diffstat: + return print_diffstat(old_tree, new_tree) + + changed_files = apply_changes( + old_tree, new_tree, force=opts.force, patch_mode=opts.patch + ) + if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1: + print("changed files:") + for filename in changed_files: + print(" %s" % filename) + + return 1 + + +def load_git_config(non_string_options=None): + """Return the git configuration as a dictionary. + + All options are assumed to be strings unless in `non_string_options`, in + which is a dictionary mapping option name (in lower case) to either "--bool" + or "--int".""" + if non_string_options is None: + non_string_options = {} + out = {} + for entry in run("git", "config", "--list", "--null").split("\0"): + if entry: + if "\n" in entry: + name, value = entry.split("\n", 1) + else: + # A setting with no '=' ('\n' with --null) is implicitly 'true' + name = entry + value = "true" + if name in non_string_options: + value = run("git", "config", non_string_options[name], name) + out[name] = value + return out + + +def interpret_args(args, dash_dash, default_commit): + """Interpret `args` as "[commits] [--] [files]" and return (commits, files). + + It is assumed that "--" and everything that follows has been removed from + args and placed in `dash_dash`. + + If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its + left (if present) are taken as commits. Otherwise, the arguments are + checked from left to right if they are commits or files. If commits are not + given, a list with `default_commit` is used.""" + if dash_dash: + if len(args) == 0: + commits = [default_commit] + else: + commits = args + for commit in commits: + object_type = get_object_type(commit) + if object_type not in ("commit", "tag"): + if object_type is None: + die("'%s' is not a commit" % commit) + else: + die( + "'%s' is a %s, but a commit was expected" + % (commit, object_type) + ) + files = dash_dash[1:] + elif args: + commits = [] + while args: + if not disambiguate_revision(args[0]): + break + commits.append(args.pop(0)) + if not commits: + commits = [default_commit] + files = args + else: + commits = [default_commit] + files = [] + return commits, files + + +def disambiguate_revision(value): + """Returns True if `value` is a revision, False if it is a file, or dies.""" + # If `value` is ambiguous (neither a commit nor a file), the following + # command will die with an appropriate error message. + run("git", "rev-parse", value, verbose=False) + object_type = get_object_type(value) + if object_type is None: + return False + if object_type in ("commit", "tag"): + return True + die("`%s` is a %s, but a commit or filename was expected" % (value, object_type)) + + +def get_object_type(value): + """Returns a string description of an object's type, or None if it is not + a valid git object.""" + cmd = ["git", "cat-file", "-t", value] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + if p.returncode != 0: + return None + return convert_string(stdout.strip()) + + +def compute_diff_and_extract_lines(commits, files, staged, diff_common_commit): + """Calls compute_diff() followed by extract_lines().""" + diff_process = compute_diff(commits, files, staged, diff_common_commit) + changed_lines = extract_lines(diff_process.stdout) + diff_process.stdout.close() + diff_process.wait() + if diff_process.returncode != 0: + # Assume error was already printed to stderr. + sys.exit(2) + return changed_lines + + +def compute_diff(commits, files, staged, diff_common_commit): + """Return a subprocess object producing the diff from `commits`. + + The return value's `stdin` file object will produce a patch with the + differences between the working directory (or stage if --staged is used) and + the first commit if a single one was specified, or the difference between + both specified commits, filtered on `files` (if non-empty). + Zero context lines are used in the patch.""" + git_tool = "diff-index" + extra_args = [] + if len(commits) == 2: + git_tool = "diff-tree" + if diff_common_commit: + commits = [f"{commits[0]}...{commits[1]}"] + elif staged: + extra_args += ["--cached"] + + cmd = ["git", git_tool, "-p", "-U0"] + extra_args + commits + ["--"] + cmd.extend(files) + p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + p.stdin.close() + return p + + +def extract_lines(patch_file): + """Extract the changed lines in `patch_file`. + + The return value is a dictionary mapping filename to a list of (start_line, + line_count) pairs. + + The input must have been produced with ``-U0``, meaning unidiff format with + zero lines of context. The return value is a dict mapping filename to a + list of line `Range`s.""" + matches = {} + for line in patch_file: + line = convert_string(line) + match = re.search(r"^\+\+\+\ [^/]+/(.*)", line) + if match: + filename = match.group(1).rstrip("\r\n\t") + match = re.search(r"^@@ -[0-9,]+ \+(\d+)(,(\d+))?", line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(3): + line_count = int(match.group(3)) + if line_count == 0: + line_count = 1 + if start_line == 0: + continue + matches.setdefault(filename, []).append(Range(start_line, line_count)) + return matches + + +def filter_by_extension(dictionary, allowed_extensions): + """Delete every key in `dictionary` that doesn't have an allowed extension. + + `allowed_extensions` must be a collection of lowercase file extensions, + excluding the period.""" + allowed_extensions = frozenset(allowed_extensions) + for filename in list(dictionary.keys()): + base_ext = filename.rsplit(".", 1) + if len(base_ext) == 1 and "" in allowed_extensions: + continue + if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions: + del dictionary[filename] + + +def filter_symlinks(dictionary): + """Delete every key in `dictionary` that is a symlink.""" + for filename in list(dictionary.keys()): + if os.path.islink(filename): + del dictionary[filename] + + +def filter_ignored_files(dictionary, binary): + """Delete every key in `dictionary` that is ignored by clang-format.""" + ignored_files = run(binary, "-list-ignored", *dictionary.keys()) + if not ignored_files: + return + ignored_files = ignored_files.split("\n") + for filename in ignored_files: + del dictionary[filename] + + +def cd_to_toplevel(): + """Change to the top level of the git repository.""" + toplevel = run("git", "rev-parse", "--show-toplevel") + os.chdir(toplevel) + + +def create_tree_from_workdir(filenames): + """Create a new git tree with the given files from the working directory. + + Returns the object ID (SHA-1) of the created tree.""" + return create_tree(filenames, "--stdin") + + +def create_tree_from_index(filenames): + # Copy the environment, because the files have to be read from the original + # index. + env = os.environ.copy() + + def index_contents_generator(): + for filename in filenames: + git_ls_files_cmd = [ + "git", + "ls-files", + "--stage", + "-z", + "--", + filename, + ] + git_ls_files = subprocess.Popen( + git_ls_files_cmd, + env=env, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout = git_ls_files.communicate()[0] + yield convert_string(stdout.split(b"\0")[0]) + + return create_tree(index_contents_generator(), "--index-info") + + +def run_clang_format_and_save_to_tree( + changed_lines, revision=None, binary="clang-format", style=None +): + """Run clang-format on each file and save the result to a git tree. + + Returns the object ID (SHA-1) of the created tree.""" + # Copy the environment when formatting the files in the index, because the + # files have to be read from the original index. + env = os.environ.copy() if revision == "" else None + + def iteritems(container): + try: + return container.iteritems() # Python 2 + except AttributeError: + return container.items() # Python 3 + + def index_info_generator(): + for filename, line_ranges in iteritems(changed_lines): + if revision is not None: + if len(revision) > 0: + git_metadata_cmd = [ + "git", + "ls-tree", + "%s:%s" % (revision, os.path.dirname(filename)), + os.path.basename(filename), + ] + else: + git_metadata_cmd = [ + "git", + "ls-files", + "--stage", + "--", + filename, + ] + git_metadata = subprocess.Popen( + git_metadata_cmd, + env=env, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout = git_metadata.communicate()[0] + mode = oct(int(stdout.split()[0], 8)) + else: + mode = oct(os.stat(filename).st_mode) + # Adjust python3 octal format so that it matches what git expects + if mode.startswith("0o"): + mode = "0" + mode[2:] + blob_id = clang_format_to_blob( + filename, + line_ranges, + revision=revision, + binary=binary, + style=style, + env=env, + ) + yield "%s %s\t%s" % (mode, blob_id, filename) + + return create_tree(index_info_generator(), "--index-info") + + +def create_tree(input_lines, mode): + """Create a tree object from the given input. + + If mode is '--stdin', it must be a list of filenames. If mode is + '--index-info' is must be a list of values suitable for "git update-index + --index-info", such as " ". Any other + mode is invalid.""" + assert mode in ("--stdin", "--index-info") + cmd = ["git", "update-index", "--add", "-z", mode] + with temporary_index_file(): + p = subprocess.Popen(cmd, stdin=subprocess.PIPE) + for line in input_lines: + p.stdin.write(to_bytes("%s\0" % line)) + p.stdin.close() + if p.wait() != 0: + die("`%s` failed" % " ".join(cmd)) + tree_id = run("git", "write-tree") + return tree_id + + +def clang_format_to_blob( + filename, + line_ranges, + revision=None, + binary="clang-format", + style=None, + env=None, +): + """Run clang-format on the given file and save the result to a git blob. + + Runs on the file in `revision` if not None, or on the file in the working + directory if `revision` is None. Revision can be set to an empty string to + run clang-format on the file in the index. + + Returns the object ID (SHA-1) of the created blob.""" + clang_format_cmd = [binary] + if style: + clang_format_cmd.extend(["--style=" + style]) + clang_format_cmd.extend( + [ + "--lines=%s:%s" % (start_line, start_line + line_count - 1) + for start_line, line_count in line_ranges + ] + ) + if revision is not None: + clang_format_cmd.extend(["--assume-filename=" + filename]) + git_show_cmd = [ + "git", + "cat-file", + "blob", + "%s:%s" % (revision, filename), + ] + git_show = subprocess.Popen( + git_show_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + git_show.stdin.close() + clang_format_stdin = git_show.stdout + else: + clang_format_cmd.extend([filename]) + git_show = None + clang_format_stdin = subprocess.PIPE + try: + clang_format = subprocess.Popen( + clang_format_cmd, stdin=clang_format_stdin, stdout=subprocess.PIPE + ) + if clang_format_stdin == subprocess.PIPE: + clang_format_stdin = clang_format.stdin + except OSError as e: + if e.errno == errno.ENOENT: + die('cannot find executable "%s"' % binary) + else: + raise + clang_format_stdin.close() + hash_object_cmd = [ + "git", + "hash-object", + "-w", + "--path=" + filename, + "--stdin", + ] + hash_object = subprocess.Popen( + hash_object_cmd, stdin=clang_format.stdout, stdout=subprocess.PIPE + ) + clang_format.stdout.close() + stdout = hash_object.communicate()[0] + if hash_object.returncode != 0: + die("`%s` failed" % " ".join(hash_object_cmd)) + if clang_format.wait() != 0: + die("`%s` failed" % " ".join(clang_format_cmd)) + if git_show and git_show.wait() != 0: + die("`%s` failed" % " ".join(git_show_cmd)) + return convert_string(stdout).rstrip("\r\n") + + +@contextlib.contextmanager +def temporary_index_file(tree=None): + """Context manager for setting GIT_INDEX_FILE to a temporary file and + deleting the file afterward.""" + index_path = create_temporary_index(tree) + old_index_path = os.environ.get("GIT_INDEX_FILE") + os.environ["GIT_INDEX_FILE"] = index_path + try: + yield + finally: + if old_index_path is None: + del os.environ["GIT_INDEX_FILE"] + else: + os.environ["GIT_INDEX_FILE"] = old_index_path + os.remove(index_path) + + +def create_temporary_index(tree=None): + """Create a temporary index file and return the created file's path. + + If `tree` is not None, use that as the tree to read in. Otherwise, an + empty index is created.""" + gitdir = run("git", "rev-parse", "--git-dir") + path = os.path.join(gitdir, temp_index_basename) + if tree is None: + tree = "--empty" + run("git", "read-tree", "--index-output=" + path, tree) + return path + + +def print_diff(old_tree, new_tree): + """Print the diff between the two trees to stdout.""" + # We use the porcelain 'diff' and not plumbing 'diff-tree' because the + # output is expected to be viewed by the user, and only the former does nice + # things like color and pagination. + # + # We also only print modified files since `new_tree` only contains the files + # that were modified, so unmodified files would show as deleted without the + # filter. + return subprocess.run( + ["git", "diff", "--diff-filter=M", "--exit-code", old_tree, new_tree] + ).returncode + + +def print_diffstat(old_tree, new_tree): + """Print the diffstat between the two trees to stdout.""" + # We use the porcelain 'diff' and not plumbing 'diff-tree' because the + # output is expected to be viewed by the user, and only the former does nice + # things like color and pagination. + # + # We also only print modified files since `new_tree` only contains the files + # that were modified, so unmodified files would show as deleted without the + # filter. + return subprocess.run( + [ + "git", + "diff", + "--diff-filter=M", + "--exit-code", + "--stat", + old_tree, + new_tree, + ] + ).returncode + + +def apply_changes(old_tree, new_tree, force=False, patch_mode=False): + """Apply the changes in `new_tree` to the working directory. + + Bails if there are local changes in those files and not `force`. If + `patch_mode`, runs `git checkout --patch` to select hunks interactively.""" + changed_files = ( + run( + "git", + "diff-tree", + "--diff-filter=M", + "-r", + "-z", + "--name-only", + old_tree, + new_tree, + ) + .rstrip("\0") + .split("\0") + ) + if not force: + unstaged_files = run("git", "diff-files", "--name-status", *changed_files) + if unstaged_files: + print( + "The following files would be modified but have unstaged changes:", + file=sys.stderr, + ) + print(unstaged_files, file=sys.stderr) + print("Please commit, stage, or stash them first.", file=sys.stderr) + sys.exit(2) + if patch_mode: + # In patch mode, we could just as well create an index from the new tree + # and checkout from that, but then the user will be presented with a + # message saying "Discard ... from worktree". Instead, we use the old + # tree as the index and checkout from new_tree, which gives the slightly + # better message, "Apply ... to index and worktree". This is not quite + # right, since it won't be applied to the user's index, but oh well. + with temporary_index_file(old_tree): + subprocess.run(["git", "checkout", "--patch", new_tree], check=True) + index_tree = old_tree + else: + with temporary_index_file(new_tree): + run("git", "checkout-index", "-f", "--", *changed_files) + return changed_files + + +def run(*args, **kwargs): + stdin = kwargs.pop("stdin", "") + verbose = kwargs.pop("verbose", True) + strip = kwargs.pop("strip", True) + for name in kwargs: + raise TypeError("run() got an unexpected keyword argument '%s'" % name) + p = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + stdout, stderr = p.communicate(input=stdin) + + stdout = convert_string(stdout) + stderr = convert_string(stderr) + + if p.returncode == 0: + if stderr: + if verbose: + print("`%s` printed to stderr:" % " ".join(args), file=sys.stderr) + print(stderr.rstrip(), file=sys.stderr) + if strip: + stdout = stdout.rstrip("\r\n") + return stdout + if verbose: + print("`%s` returned %s" % (" ".join(args), p.returncode), file=sys.stderr) + if stderr: + print(stderr.rstrip(), file=sys.stderr) + sys.exit(2) + + +def die(message): + print("error:", message, file=sys.stderr) + sys.exit(2) + + +def to_bytes(str_input): + # Encode to UTF-8 to get binary data. + if isinstance(str_input, bytes): + return str_input + return str_input.encode("utf-8") + + +def to_string(bytes_input): + if isinstance(bytes_input, str): + return bytes_input + return bytes_input.encode("utf-8") + + +def convert_string(bytes_input): + try: + return to_string(bytes_input.decode("utf-8")) + except AttributeError: # 'str' object has no attribute 'decode'. + return str(bytes_input) + except UnicodeError: + return str(bytes_input) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/frontend/src/common/prettier/plugins/clang/index.ts b/frontend/src/common/prettier/plugins/clang/index.ts new file mode 100644 index 0000000..8ceb1cd --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/index.ts @@ -0,0 +1,155 @@ +/** + * Prettier Plugin for C/C++ formatting using clang-format WebAssembly + * + * This plugin provides support for formatting C/C++ files using the clang-format WASM implementation. + * It supports various C/C++ file extensions and common clang-format styles. + */ +import type { Plugin, Parser, Printer } from 'prettier'; + +// Import the clang-format WASM module +import clangFormatInit, { format } from './clang-format-vite.js'; + +const parserName = 'clang'; + +// Language configuration +const languages = [ + { + name: 'C', + aliases: ['c'], + parsers: [parserName], + extensions: ['.c', '.h'], + aceMode: 'c_cpp', + tmScope: 'source.c', + linguistLanguageId: 50, + vscodeLanguageIds: ['c'] + }, + { + name: 'C++', + aliases: ['cpp', 'cxx', 'cc'], + parsers: [parserName], + extensions: ['.cpp', '.cxx', '.cc', '.hpp', '.hxx', '.hh', '.C', '.H'], + aceMode: 'c_cpp', + tmScope: 'source.cpp', + linguistLanguageId: 43, + vscodeLanguageIds: ['cpp'] + }, + { + name: 'Objective-C', + aliases: ['objc', 'objectivec'], + parsers: [parserName], + extensions: ['.m', '.mm'], + aceMode: 'objectivec', + tmScope: 'source.objc', + linguistLanguageId: 259, + vscodeLanguageIds: ['objective-c'] + } +]; + +// Parser configuration +const clangParser: Parser = { + astFormat: parserName, + parse: (text: string) => text, + locStart: () => 0, + locEnd: (node: string) => node.length, +}; + +// Initialize clang-format WASM module +let initPromise: Promise | null = null; +let isInitialized = false; + +function initClangFormat(): Promise { + if (initPromise) { + return initPromise; + } + + initPromise = (async () => { + if (!isInitialized) { + await clangFormatInit(); + isInitialized = true; + } + })(); + + return initPromise; +} + +// Printer configuration +const clangPrinter: Printer = { + print: (path, options) => { + try { + if (!isInitialized) { + console.warn('clang-format WASM module not initialized, returning original text'); + return (path as any).getValue ? (path as any).getValue() : path.node; + } + + const text = (path as any).getValue ? (path as any).getValue() : path.node; + const style = getClangStyle(options); + + // Format using clang-format (synchronous call) + const formatted = format(text, undefined, style); + + return formatted.trim(); + } catch (error) { + console.warn('clang-format failed:', error); + // Return original text if formatting fails + return (path as any).getValue ? (path as any).getValue() : path.node; + } + }, +}; + + +// Helper function to determine clang-format style +function getClangStyle(options: any): string { + // You can extend this to support more options + const style = options.clangStyle || 'LLVM'; + + // Support common styles + const validStyles = ['LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit', 'Microsoft', 'GNU']; + if (validStyles.includes(style)) { + return style; + } + + // Default to LLVM style + return 'LLVM'; +} + +// Plugin options +const options = { + clangStyle: { + since: '0.0.1', + category: 'Format' as const, + type: 'choice' as const, + default: 'LLVM', + description: 'The clang-format style to use', + choices: [ + { value: 'LLVM', description: 'LLVM coding standards' }, + { value: 'Google', description: "Google's C++ style guide" }, + { value: 'Chromium', description: "Chromium's style guide" }, + { value: 'Mozilla', description: "Mozilla's style guide" }, + { value: 'WebKit', description: "WebKit's style guide" }, + { value: 'Microsoft', description: "Microsoft's style guide" }, + { value: 'GNU', description: 'GNU coding standards' } + ] + } +}; + +// Plugin object +const clangPlugin: Plugin = { + languages, + parsers: { + [parserName]: clangParser, + }, + printers: { + [parserName]: clangPrinter, + }, + options, +}; + +// Initialize WASM module when plugin loads +initClangFormat().catch(error => { + console.warn('Failed to initialize clang-format WASM module:', error); +}); + +export default clangPlugin; +export { languages }; +export const parsers = clangPlugin.parsers; +export const printers = clangPlugin.printers; diff --git a/frontend/src/common/prettier/plugins/clang/lib.cc b/frontend/src/common/prettier/plugins/clang/lib.cc new file mode 100644 index 0000000..5739559 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/lib.cc @@ -0,0 +1,323 @@ +//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a clang-format tool that automatically formats +/// (fragments of) C++ code. +/// +//===----------------------------------------------------------------------===// + +#include "lib.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Format/Format.h" +#include "clang/Rewrite/Core/Rewriter.h" + +using namespace llvm; +using clang::tooling::Replacements; + +static std::string FallbackStyle{clang::format::DefaultFallbackStyle}; + +static unsigned Cursor{0}; + +static bool SortIncludes{false}; + +static std::string QualifierAlignment{""}; + +static auto Ok(const std::string content) -> Result { + return {false, std::move(content)}; +} + +static auto Err(const std::string content) -> Result { + return {true, std::move(content)}; +} + +namespace clang { +namespace format { + +static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source, + SourceManager &Sources, FileManager &Files, + llvm::vfs::InMemoryFileSystem *MemFS) { + MemFS->addFileNoOwn(FileName, 0, Source); + auto File = Files.getOptionalFileRef(FileName); + assert(File && "File not added to MemFS?"); + return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User); +} + +static auto fillRanges(MemoryBuffer *Code, std::vector &Ranges) + -> void { + Ranges.push_back(tooling::Range(0, Code->getBuffer().size())); +} + +static auto isPredefinedStyle(StringRef style) -> bool { + return StringSwitch(style.lower()) + .Cases("llvm", "chromium", "mozilla", "google", "webkit", "gnu", + "microsoft", "none", "file", true) + .Default(false); +} + +static auto format_range(const std::unique_ptr code, + const std::string assumedFileName, + const std::string style, + std::vector ranges) -> Result { + StringRef BufStr = code->getBuffer(); + + const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr); + + if (InvalidBOM) { + std::stringstream err; + err << "encoding with unsupported byte order mark \"" << InvalidBOM + << "\" detected."; + + return Err(err.str()); + } + + StringRef AssumedFileName = assumedFileName; + if (AssumedFileName.empty()) + AssumedFileName = ""; + + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts); + SourceManager Sources(Diagnostics, Files); + + StringRef _style = style; + + if (!_style.starts_with("{") && !isPredefinedStyle(_style)) { + std::unique_ptr DotClangFormat = + MemoryBuffer::getMemBuffer(style); + + createInMemoryFile(".clang-format", *DotClangFormat.get(), Sources, Files, + InMemoryFileSystem.get()); + _style = "file:.clang-format"; + } + + llvm::Expected FormatStyle = + getStyle(_style, AssumedFileName, FallbackStyle, code->getBuffer(), + InMemoryFileSystem.get(), false); + + InMemoryFileSystem.reset(); + + if (!FormatStyle) { + std::string err = llvm::toString(FormatStyle.takeError()); + return Err(err); + } + + StringRef QualifierAlignmentOrder = QualifierAlignment; + + FormatStyle->QualifierAlignment = + StringSwitch( + QualifierAlignmentOrder.lower()) + .Case("right", FormatStyle::QAS_Right) + .Case("left", FormatStyle::QAS_Left) + .Default(FormatStyle->QualifierAlignment); + + if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) { + FormatStyle->QualifierOrder = {"const", "volatile", "type"}; + } else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) { + FormatStyle->QualifierOrder = {"type", "const", "volatile"}; + } else if (QualifierAlignmentOrder.contains("type")) { + FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom; + SmallVector Qualifiers; + QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()}; + } + + if (SortIncludes) { + FormatStyle->SortIncludes = {}; + FormatStyle->SortIncludes.Enabled = true; + } + + unsigned CursorPosition = Cursor; + Replacements Replaces = sortIncludes(*FormatStyle, code->getBuffer(), ranges, + AssumedFileName, &CursorPosition); + + // To format JSON insert a variable to trick the code into thinking its + // JavaScript. + if (FormatStyle->isJson() && !FormatStyle->DisableFormat) { + auto err = + Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = ")); + if (err) + return Err("Bad Json variable insertion"); + } + + auto ChangedCode = + cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces)); + + // Get new affected ranges after sorting `#includes`. + ranges = tooling::calculateRangesAfterReplacements(Replaces, ranges); + FormattingAttemptStatus Status; + Replacements FormatChanges = + reformat(*FormatStyle, ChangedCode, ranges, AssumedFileName, &Status); + Replaces = Replaces.merge(FormatChanges); + + return Ok( + cantFail(tooling::applyAllReplacements(code->getBuffer(), Replaces))); +} + +static auto format_range(const std::string str, + const std::string assumedFileName, + const std::string style, const bool is_line_range, + const std::vector ranges) -> Result { + ErrorOr> CodeOrErr = + MemoryBuffer::getMemBuffer(str); + + if (std::error_code EC = CodeOrErr.getError()) + return Err(EC.message()); + std::unique_ptr Code = std::move(CodeOrErr.get()); + if (Code->getBufferSize() == 0) + return Ok(""); // Empty files are formatted correctly. + + std::vector Ranges; + + if (ranges.empty()) { + fillRanges(Code.get(), Ranges); + return format_range(std::move(Code), assumedFileName, style, + std::move(Ranges)); + } + + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts); + SourceManager Sources(Diagnostics, Files); + FileID ID = createInMemoryFile("", *Code, Sources, Files, + InMemoryFileSystem.get()); + + if (is_line_range) { + for (auto FromLine = begin(ranges); FromLine < end(ranges); FromLine += 2) { + auto ToLine = FromLine + 1; + + SourceLocation Start = Sources.translateLineCol(ID, *FromLine, 1); + SourceLocation End = Sources.translateLineCol(ID, *ToLine, UINT_MAX); + if (Start.isInvalid() || End.isInvalid()) + return Err("invalid line number"); + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); + } + } else { + if (ranges.size() > 2 && ranges.size() % 2 != 0) + return Err("number of -offset and -length arguments must match"); + + if (ranges.size() == 1) { + auto offset = begin(ranges); + if (*offset >= Code->getBufferSize()) { + std::stringstream err; + err << "offset " << *offset << " is outside the file"; + return Err(err.str()); + } + SourceLocation Start = + Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset); + SourceLocation End = Sources.getLocForEndOfFile(ID); + + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + + Ranges.push_back(tooling::Range(Offset, Length)); + } else { + for (auto offset = begin(ranges); offset < end(ranges); offset += 2) { + auto length = offset + 1; + + if (*offset >= Code->getBufferSize()) { + std::stringstream err; + err << "offset " << *offset << " is outside the file"; + return Err(err.str()); + } + + unsigned end = *offset + *length; + if (end > Code->getBufferSize()) { + std::stringstream err; + err << "invalid length " << *length << ", offset + length (" << end + << ") is outside the file."; + return Err(err.str()); + } + + SourceLocation Start = + Sources.getLocForStartOfFile(ID).getLocWithOffset(*offset); + SourceLocation End = Start.getLocWithOffset(*length); + + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + + Ranges.push_back(tooling::Range(Offset, Length)); + } + } + } + + return format_range(std::move(Code), assumedFileName, style, + std::move(Ranges)); +} + +static auto format(const std::string str, const std::string assumedFileName, + const std::string style) -> Result { + ErrorOr> CodeOrErr = + MemoryBuffer::getMemBuffer(str); + + if (std::error_code EC = CodeOrErr.getError()) + return Err(EC.message()); + std::unique_ptr Code = std::move(CodeOrErr.get()); + if (Code->getBufferSize() == 0) + return Ok(""); // Empty files are formatted correctly. + + std::vector Ranges; + fillRanges(Code.get(), Ranges); + + return format_range(std::move(Code), assumedFileName, style, + std::move(Ranges)); +} + +} // namespace format +} // namespace clang + +auto version() -> std::string { + return clang::getClangToolFullVersion("clang-format"); +} + +auto format(const std::string str, const std::string assumedFileName, + const std::string style) -> Result { + return clang::format::format(str, assumedFileName, style); +} + +auto format_byte(const std::string str, const std::string assumedFileName, + const std::string style, const std::vector ranges) + -> Result { + return clang::format::format_range(str, assumedFileName, style, false, + std::move(ranges)); +} + +auto format_line(const std::string str, const std::string assumedFileName, + const std::string style, const std::vector ranges) + -> Result { + return clang::format::format_range(str, assumedFileName, style, true, + std::move(ranges)); +} + +auto set_fallback_style(const std::string style) -> void { + FallbackStyle = style; +} + +auto set_sort_includes(const bool sort) -> void { SortIncludes = sort; } + +auto dump_config(const std::string style, const std::string FileName, + const std::string code) -> Result { + llvm::Expected FormatStyle = + clang::format::getStyle(style, FileName, FallbackStyle, code); + if (!FormatStyle) + return Err(llvm::toString(FormatStyle.takeError())); + std::string Config = clang::format::configurationAsText(*FormatStyle); + return Ok(Config); +} diff --git a/frontend/src/common/prettier/plugins/clang/lib.h b/frontend/src/common/prettier/plugins/clang/lib.h new file mode 100644 index 0000000..b84cb77 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/lib.h @@ -0,0 +1,24 @@ +#ifndef CLANG_FORMAT_WASM_LIB_H_ +#define CLANG_FORMAT_WASM_LIB_H_ +#include + +struct Result { + bool error; + std::string content; +}; + +auto version() -> std::string; +auto format(const std::string str, const std::string assumedFileName, const std::string style) -> Result; +auto format_byte(const std::string str, + const std::string assumedFileName, + const std::string style, + const std::vector ranges) -> Result; +auto format_line(const std::string str, + const std::string assumedFileName, + const std::string style, + const std::vector ranges) -> Result; +auto set_fallback_style(const std::string style) -> void; +auto set_sort_includes(const bool sort) -> void; +auto dump_config(const std::string style, const std::string FileName, const std::string code) -> Result; + +#endif diff --git a/frontend/src/common/prettier/plugins/clang/template.js b/frontend/src/common/prettier/plugins/clang/template.js new file mode 100644 index 0000000..07acad1 --- /dev/null +++ b/frontend/src/common/prettier/plugins/clang/template.js @@ -0,0 +1,146 @@ +/* @ts-self-types="./clang-format.d.ts" */ +async function load(module) { + if (typeof Response === "function" && module instanceof Response) { + if ("compileStreaming" in WebAssembly) { + try { + return await WebAssembly.compileStreaming(module); + } catch (e) { + if (module.headers.get("Content-Type") !== "application/wasm") { + console.warn( + "`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", + e, + ); + } else { + throw e; + } + } + } + + return module.arrayBuffer(); + } + + return module; +} + +let wasm; +export default async function initAsync(input) { + if (wasm !== undefined) { + return wasm; + } + + if (typeof input === "undefined") { + input = new URL("clang-format.wasm", import.meta.url); + } + + if ( + typeof input === "string" || + (typeof Request === "function" && input instanceof Request) || + (typeof URL === "function" && input instanceof URL) + ) { + input = fetch(input); + } + + wasm = await load(await input).then((wasm) => Module({ wasm })); + assert_init = () => {}; +} + +function assert_init() { + throw new Error("uninit"); +} + +export function version() { + assert_init(); + return wasm.version(); +} + +export function set_fallback_style(style) { + assert_init(); + wasm.set_fallback_style(style); +} + +export function set_sort_includes(sort) { + assert_init(); + wasm.set_sort_includes(sort); +} + +function unwrap(result) { + const { error, content } = result; + if (error) { + throw Error(content); + } + return content; +} + +export function format(content, filename = "", style = "LLVM") { + assert_init(); + const result = wasm.format(content, filename, style); + return unwrap(result); +} + +export function format_line_range( + content, + range, + filename = "", + style = "LLVM", +) { + assert_init(); + const rangeList = new wasm.RangeList(); + for (const [fromLine, toLine] of range) { + if (fromLine < 1) { + throw Error("start line should be at least 1"); + } + if (fromLine > toLine) { + throw Error("start line should not exceed end line"); + } + rangeList.push_back(fromLine); + rangeList.push_back(toLine); + } + + const result = wasm.format_line(content, filename, style, rangeList); + rangeList.delete(); + return unwrap(result); +} + +export function format_byte_range( + content, + range, + filename = "", + style = "LLVM", +) { + assert_init(); + const rangeList = new wasm.RangeList(); + + if (range.length === 1 && range[0].length === 1) { + rangeList.push_back(range[0][0]); + } else { + for (const [offset, length] of range) { + if (offset < 0) { + throw Error("start offset should be at least 0"); + } + if (length < 0) { + throw Error("length should be at least 0"); + } + rangeList.push_back(offset); + rangeList.push_back(length); + } + } + + const result = wasm.format_byte(content, filename, style, rangeList); + rangeList.delete(); + return unwrap(result); +} + +export function dump_config({ + style = "file", + filename = "", + code = "", +} = {}) { + assert_init(); + const result = wasm.dump_config(style, filename, code); + return unwrap(result); +} + +export { + format_byte_range as formatByteRange, + format_line_range as formatLineRange, +}; diff --git a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts index 59d40c5..d8fa95f 100644 --- a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts +++ b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts @@ -47,6 +47,7 @@ import tomlPrettierPlugin from "@/common/prettier/plugins/toml"; import clojurePrettierPlugin from "@cospaia/prettier-plugin-clojure"; import groovyPrettierPlugin from "@/common/prettier/plugins/groovy"; import scalaPrettierPlugin from "@/common/prettier/plugins/scala"; +import clangPrettierPlugin from "@/common/prettier/plugins/clang"; import * as prettierPluginEstree from "prettier/plugins/estree"; /** @@ -102,7 +103,10 @@ export const LANGUAGES: LanguageInfo[] = [ parser: "xml", plugins: [xmlPrettierPlugin] }), - new LanguageInfo("cpp", "C++", cppLanguage.parser), + new LanguageInfo("cpp", "C++", cppLanguage.parser,{ + parser: "clang", + plugins: [clangPrettierPlugin] + }), new LanguageInfo("rs", "Rust", rustLanguage.parser,{ parser: "jinx-rust", plugins: [rustPrettierPlugin]