SCAST MCP Server

by davidkingzyb
Verified
var SCAST=function(){var types={num:false,kw:false,id:false,str:false,punc:false,sp:false,op:false,t:false,Comment:false,ClassDefine:true,InterfaceDefine:true,NamespaceDefine:true,MethodDefine:true,PropertyDefine:true,Variable:true,NewExpression:true,CallExpression:true,FunctionDefine:true,LoopStatement:true,IfStatement:true,BlockStatement:true,Expression:false,Condition:false,Arguments:false,Arg:false,ArrayExpression:true,ObjectExpression:true,TupleExpression:true,WithStatement:true,MemberExpression:true,TryStatement:true,ExceptStatement:true,FinallyStatement:true,Lambda:true};function TokenStream(input){var current=null;var prev_id=null;var keywords=["break","do","in","typeof","case","else","instanceof","var","catch","export","new","void","class","extends","return","while","const","finally","super","with","continue","for","switch","yield","debugger","function","this","default","if","throw","delete","import","try","constructor","super"];var cskeywords=["abstract","as","base","bool","break","byte","case","catch","char","checked","class","const","continue","decimal","default","delegate","do","double","else","enum","event","explicit","extern","false","finally","fixed","float","for","foreach","goto","if","implicit","in","int","interface","internal","is","lock","long","namespace","new","null","object","operator","out","override","params","private","protected","public","readonly","ref","return","sbyte","sealed","short","sizeof","stackalloc","static","string","struct","switch","this","throw","true","try","typeof","uint","ulong","unchecked","unsafe","ushort","using","virtual","void","volatile","while","add","and","alias","ascending","args","async","await","by","descending","dynamic","equals","from","get","global","group","init","into","join","let","nameof","nint","not","notnull","nuint","on","or","orderby","partial","partial","record","remove","select","set","unmanaged","value","var","when","where","with","yield"];return{next:next,peek:peek,prev:prev,eof:eof,croak:input.croak};function is_keyword(x){return keywords.indexOf(x)>=0||cskeywords.indexOf(x)>=0}function is_digit(ch){return/[0-9]/i.test(ch)}function is_id_start(ch){return/[a-zA-Z$_]/i.test(ch)}function is_id(ch){return is_id_start(ch)||"0123456789".indexOf(ch)>=0}function is_op_char(ch){return"+-*/%=&|<>!^\\".indexOf(ch)>=0}function is_punc(ch){return"(){}[]".indexOf(ch)>=0}function is_whitespace(ch){return" \t\n".indexOf(ch)>=0}function is_split(ch){return",;.:?".indexOf(ch)>=0}function read_while(predicate){var str="";while(!input.eof()&&predicate(input.peek()))str+=input.next();return str}function read_number(){var has_dot=false;var number=read_while(function(ch){if(ch=="."){if(has_dot)return false;has_dot=true;return true}return is_digit(ch)});return{type:"num",value:parseFloat(number),poi:{line:start.line,start:start.column,end:input.poi().column}}}function read_ident(){var id=read_while(is_id);return{type:is_keyword(id)?"kw":"id",value:id,poi:{line:start.line,start:start.column,end:input.poi().column}}}function read_escaped(end){var escaped=false,str="";input.next();while(!input.eof()){var ch=input.next();if(escaped){str+=ch;escaped=false}else if(ch=="\\"){escaped=true}else if(ch==end){break}else{str+=ch}}return str}function read_string(ch){return{type:"str",value:read_escaped(ch),poi:{line:start.line,start:start.column,end:input.poi().column}}}function skip_comment(){read_while(function(ch){return ch!="\n"});input.next()}var start;function read_next(){read_while(is_whitespace);if(input.eof())return null;var ch=input.peek();start=input.poi();if(ch=="#"||ch=="/"&&input.peek(1)=="/"){return{type:"Comment",value:read_while(function(ch){return ch!="\n"}),poi:{line:start.line,start:start.column,end:input.poi().column}}}if(ch=='"')return read_string('"');if(ch=="'")return read_string("'");if(ch=="`")return read_string("`");if(is_digit(ch))return read_number();if(is_id_start(ch))return read_ident();if(is_punc(ch))return{type:"punc",value:input.next(),poi:{line:start.line,start:start.column,end:input.poi().column}};if(is_split(ch))return{type:"sp",value:input.next(),poi:{line:start.line,start:start.column,end:input.poi().column}};if(is_op_char(ch))return{type:"op",value:read_while(is_op_char),poi:{line:start.line,start:start.column,end:input.poi().column}};input.croak(`Can't handle character :${ch}(${ch.charCodeAt(0)})`)}function peek(){return current||(current=read_next())}function next(){var tok=current;if(current?.type=="id")prev_id=current;current=null;return tok||read_next()}function prev(){return prev_id}function eof(){return peek()==null}}function parse(input){return parse_toplevel();function is_punc(ch){var tok=input.peek();return tok&&tok.type=="punc"&&(!ch||tok.value==ch)&&tok}function is_sp(ch){var tok=input.peek();return tok&&tok.type=="sp"&&(!ch||tok.value==ch)&&tok}function is_kw(kw){var tok=input.peek();return tok&&tok.type=="kw"&&(!kw||tok.value==kw)&&tok}function is_op(op){var tok=input.peek();return tok&&tok.type=="op"&&(!op||tok.value==op)&&tok}function is_id(){var tok=input.peek();return tok.type=="id"}function is_num(){var tok=input.peek();return tok.type=="num"}function is_str(){var tok=input.peek();return tok.type=="str"}function skip_punc(ch){if(is_punc(ch))input.next();else input.croak('Expecting punctuation: "'+ch+'"')}function skip_split(ch){if(is_sp(ch))input.next();else input.croak('Expecting punctuation: "'+ch+'"')}function unexpected(){input.croak("Unexpected token: "+JSON.stringify(input.peek()))}function parse_next(){var n=input.next();return n}function parse_toplevel(){var prog=[];while(!input.eof()){prog.push(parse_statement())}return{type:"top",body:prog}}function parse_block(){var poi={line:input.peek().poi.line,start:input.peek().poi.start};var body=[];skip_punc("{");while(!is_punc("}")){var sts=parse_statement();sts&&body.push(sts)}skip_punc("}");return{type:"BlockStatement",body:body,poi:poi}}function parse_arguments(){var r={type:"Arguments",body:[],poi:{line:input.peek().poi.line,start:input.peek().poi.start},value:""};skip_punc("(");while(!is_punc(")")){var sts=parse_arg();if(sts){r.value+=sts.value+" ";r.body.push(sts)}}skip_punc(")");return r}function parse_arg(){if(is_sp(","))return skip_split(",");if(is_punc("{"))return parse_block();let n=null;let prevv=input.prev();if(is_id()){n=input.next();if(is_punc("(")){return{type:"CallExpression",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_arguments()],callee:prevv}}}else if(is_kw("function")){n=input.next();if(is_punc("(")){return{type:"CallExpression",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_arguments()],callee:prevv}}}else{n=input.next()}return{type:"Arg",value:n.value,node:n,poi:n.poi}}function is_define(ch){var tok=input.peek();var keywords=["public","private","protected","sealed","internal","static","class","interface","namespace"];return tok&&tok.type=="kw"&&(!ch&&keywords.indexOf(tok.value)>=0||tok.value==ch)&&tok}function parse_define(){var r={type:"",level:input.peek().value,is_sp:false,ids:[],return_type:null,value:null,nodes:[],poi:{start:input.peek().poi.start,line:input.peek().poi.line}};while(!(is_punc("(")||is_punc("{")||is_op("=")||is_sp(";"))){r.nodes.push(input.peek());if(is_sp(":")||is_kw("extends")||is_kw("implements")){r.is_sp=true}else if(is_kw("class")){r.type="ClassDefine"}else if(is_kw("interface")){r.type="InterfaceDefine"}else if(is_kw("namespace")){r.type="NamespaceDefine"}else if(is_kw("void")){r.return_type="void"}var n=input.next();if(n.type=="id"){r.ids.push(n.value)}}if(is_punc("(")){r.type="MethodDefine";r.value=r.ids.slice(-1)[0];if(!r.return_type){r.return_type=r.ids[0]}r.parameter=parse_arguments();if(is_sp(":")){input.next();r.base=input.peek();input.next();if(is_punc("("))r.base.parameter=parse_arguments()}if(is_punc("{"))r.body=parse_block().body}else if(r.type=="ClassDefine"||r.type=="InterfaceDefine"||r.type=="NamespaceDefine"){r.value=r.ids[0];if(r.is_sp){r.extends=r.ids.slice(1)}if(is_punc("{"))r.body=parse_block().body}else if(!r.type){r.type="PropertyDefine";r.value=r.ids.slice(-1)[0];if(is_op("=")){r.body=[parse_variable(r.value)]}}return r}function parse_condition(){var r={type:"Condition",poi:{line:input.peek().poi.line,start:input.peek().poi.start},value:"",body:[]};skip_punc("(");while(!is_punc(")")){let n=null;if(is_id()){let prevv=input.prev().value;let np=input.peek().value;r.value+=np+" ";n=input.next();if(is_punc("(")){r.body.push({type:"CallExpression",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_arguments()],callee:prevv})}continue}else{n=input.next()}r.value+=n.value+" ";r.body.push(n)}skip_punc(")");return r}function parse_loop(){var n=input.next();if(is_punc("(")){r={type:"LoopStatement",value:n.value,poi:{line:n.poi.line,start:n.poi.start},condition:parse_condition()};if(is_punc("{"))r.body=parse_block().body;return r}else{console.warn("parse loop",input.peek());return n}}function parse_if(){var n=input.next();var r={type:"IfStatement",poi:{line:n.poi.line,start:n.poi.start},value:n.value};if(is_kw("if")){r.value="elif";input.next()}if(is_punc("(")){r.condition=parse_condition();if(is_punc("{")){r.body=parse_block().body}else{r.body=[until_next_kw()];return r}return r}if(is_punc("{"))r.body=parse_block().body;return r}function until_next_kw(){let _body=[];var r={type:"Expression",poi:{line:input.peek().poi.line,start:input.peek().poi.start}};while(is_num()||is_str()||is_op()||is_sp()||is_punc("(")||is_punc(")")||is_id()){let prevv=input.prev().value;let n=input.next();if(np.type=="id"&&is_punc("(")){_body.push({type:"CallExpression",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_arguments()],callee:prevv})}else{_body.push(n)}if(input.eof())break}r.body=_body;return r}function parse_variable(var_name){var n=input.next();if(is_kw("new"))return parse_new();else if(is_kw("function")){var nn=input.next();var _r={type:"FunctionDefine",value:var_name,poi:{line:nn.poi.line,start:nn.poi.start}};if(is_punc("("))_r.arguments=parse_arguments();if(is_punc("{"))_r.body=[parse_block()];return _r}else if(is_punc("{"))return parse_block();else return until_next_kw()}function parse_id(){var prevv=input.prev();var n=input.next();if(is_punc("(")){var r={type:"CallExpression",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_arguments()],callee:prevv};if(is_punc("{")){r.type="FunctionDefine";r.body=parse_block().body}return r}else if(is_op("=")){var r={type:"Variable",value:n.value,poi:{line:n.poi.line,start:n.poi.start},body:[parse_variable(n.value)]};return r}else{return n}}function parse_new(){var n=input.next();if(is_id()){var r={type:"NewExpression",value:input.peek().value,poi:{line:n.poi.line,start:n.poi.start}};var nn=input.next();if(is_punc("(")){r.body=[parse_arguments()];return r}else if(input.peek().value=="<"){r.T=input.next();return r}else if(is_sp(".")){return parse_new()}else if(is_punc("{")){r.block=parse_block();return r}else{return nn}}else{console.warn("parse new",input.peek());return n}}function parse_expression(){if(is_punc("("))return parse_arguments();else if(is_punc("{"))return parse_block();else if(is_kw("new"))return parse_new();else if(is_id())return parse_id();else return parse_next()}function parse_statement(){try{if(is_punc(";"))skip_punc(";");else if(is_define())return parse_define();else if(is_kw("for")||is_kw("while")||is_kw("foreach"))return parse_loop();else if(is_kw("if")||is_kw("else")||is_kw("switch"))return parse_if();else return parse_expression()}catch(err){var p=input.peek();console.warn(`parse statement ${p.type} ${p.value} at ${p.poi.line}:${p.poi.start}:${p.poi.end}`,err)}}}function InputStream(input){var pos=0,line=1,col=0;return{next:next,peek:peek,eof:eof,croak:croak,poi:poi};function next(){var ch=input.charAt(pos++);if(ch=="\n")line++,col=0;else col++;return ch}function peek(i=0){return input.charAt(pos+i)}function poi(){return{line:line,column:col,pos:pos}}function eof(){return peek()==""}function croak(msg){throw new Error(msg+" ("+line+":"+col+")")}}function getAst(code){var inputSteam=InputStream(code);var tokenSteam=TokenStream(inputSteam);return parse(tokenSteam)}function traverseAst(node,callback){callback&&callback(node);if(node.body&&node.body.length>0){for(let n of node.body){traverseAst(n,callback)}}}function analysisMermaid(node,file,r){switch(node.type){case"ClassDefine":if(!r.showMethod)break;if(r.FlowFilter[node.value]===false)break;r.Flow+=` ${node.value}[${node.value}]\nclick ${node.value} "javascript:void(onFlowClick('${node.value}','${file}'))"\n`;r.FDPNode[node.value]={id:node.value,w:node.value.length*d3config.fontsize/1.6+d3config.fontsize*2,text:`[${node.value}]`};traverseClass(node,file);break;case"InterfaceDefine":if(!r.showMethod)break;if(r.FlowFilter[node.value]===false)break;r.Flow+=` ${node.value}{{${node.value}}}\nclick ${node.value} "javascript:void(onFlowClick('${node.value}','${file}'))"\n`;r.FDPNode[node.value]={id:node.value,w:node.value.length*d3config.fontsize/1.6+d3config.fontsize*2,text:`{${node.value}}`};traverseClass(node,file);break;case"NamespaceDefine":if(!r.showMethod)break;if(!r.showNamespace)break;if(namespace){r.Flow+=` end\n subgraph ${node.value}.namespace\n`}else{r.Flow+=` subgraph ${node.value}.namespace\n`;namespace=node.value}break;case"FunctionDefine":if(r.showMethod)break;traverseMethod(node,{},file);break;case"MethodDefine":if(r.showMethod)break;traverseMethod(node,{},file);break;case"Variable":if(r.showMethod)break;traverseVariable(node,{},file);break}function traverseClass(node,file){node._file=file;r.FlowNode[node.value]=node;if(r.FlowOne[node.value]){if(r.FlowOne[node.value].indexOf(node.value)<0){r.FlowOne[node.value].unshift(node.value)}}else{r.FlowOne[node.value]=[node.value]}r.UMLClass[node.value]={};var level_symbol={public:"+",private:"-",protected:"#",internal:"~",static:"$"};r.UML+=` class ${node.value}{\n`;for(let member of node.body){let symbol=member.level&&level_symbol[member.level]?level_symbol[member.level]:" ";switch(member.type){case"PropertyDefine":traverseProperty(member,node,file,symbol);break;case"MethodDefine":traverseMethod(member,node,file,symbol);break;case"FunctionDefine":traverseMethod(member,node,file,symbol);break}}r.UML+=" }\n";if(node.extends){for(let f of node.extends){if(r.FlowNode[f]&&r.FlowNode[f].type=="InterfaceDefine"){r.FDPNode[f]={id:f,w:f.length*d3config.fontsize/1.6+d3config.fontsize*2,text:`{${f}}`};r.UML+=` ${f} <|.. ${node.value}\n`;r.FlowLink+=`${f} ==> ${node.value}\n`;r.FDPLinks.push({source:node.value,target:f,value:6,dist:200,dash:"2,2"})}else{if(r.FDPNode[f]===undefined)r.FDPNode[f]={id:f,w:f.length*d3config.fontsize/1.6+d3config.fontsize*2,text:`[${f}]`};r.UML+=` ${f} <|-- ${node.value}\n`;r.FlowLink+=`${f} ==o ${node.value}\n`;r.FDPLinks.push({source:f,target:node.value,value:6,dist:200,dash:"2,2"})}}}}function traverseProperty(member,cls,file,symbol){member._flow_id=member.value+"_"+cls.value;member._flow_from=cls.value;member._flow_prop=`|${symbol}${member.value.replaceAll("|","|").replaceAll("[","").replaceAll("]","")}|`;member._file=file;if(r.FlowFilter[member._flow_id]===false)return;r.FlowNode[member._flow_id]=member;r.UML+=` ${symbol}${member.value}\n`;if(r.showCall)_doBody(member,file);function _doBody(node,file){if(!node.body)return;for(let n of node.body){n._file=file;n._flow_id=n.value+"_"+node._flow_id;n._flow_from=node._flow_from;n._flow_prop=node._flow_prop;r.FlowNode[n._flow_id]=n;if(n.type=="Expression"){n._flow_id=node._flow_id;_doBody(n,file)}else if(r.FlowFilter[n._flow_id]&&(n.type=="NewExpression"||n.type=="CallExpression")){if(n.type=="NewExpression"){r.UMLClass[cls.value][n._flow_id]=n;n._flow_str=` ${n._flow_id}[${n.value}]\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6,text:`${n.value}`};r.FlowVarNew[node.value]=n.value}else{n._flow_str=` ${n._flow_id}([${n.value}])\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6+d3config.fontsize*2,text:`${n.value}()`}}r.Flow+=n._flow_str}}}}function traverseMethod(member,cls,file,symbol){var method=cls.value?member.value+"_"+cls.value:member.value;if(r.FlowOne[member.value]){if(r.FlowOne[member.value].indexOf(method)<0){r.FlowOne[member.value].unshift(method)}}else{r.FlowOne[member.value]=[method]}member._flow_id=method;member._flow_from=cls.value;member._file=file;if(r.FlowFilter[member._flow_id]===false)return;r.FlowNode[member._flow_id]=member;r.FDPNode[member._flow_id]={id:member._flow_id,w:member.value.length*d3config.fontsize/1.6+d3config.fontsize*3,text:`${symbol||":"}${member.value}()`};if(symbol)r.UML+=` ${symbol}${member.value}()\n`;if(member.base||member.value==cls.value){r.Flow+=` ${member._flow_id}(${member.value})\nclick ${member._flow_id} "javascript:void(onFlowClick('${member._flow_id}','${file}'))"\n`}else{r.Flow+=` ${member._flow_id}([${member.value}])\nclick ${member._flow_id} "javascript:void(onFlowClick('${member._flow_id}','${file}'))"\n`}if(cls.value){r.FlowLink+=`${cls.value} --o ${member._flow_id}\n`;r.FDPLinks.push({source:cls.value,target:member._flow_id,value:2})}if(r.showCall)_doBody(member,file);function _doBody(node,file){if(!node.body)return;for(let n of node.body){n._file=file;n._flow_id=n.value+"_"+node._flow_id;n._flow_from=r.showIf?node._flow_id:method;if(n.type=="IfStatement"||n.type=="LoopStatement"){if(r.showIf){r.Flow+=n.type=="IfStatement"?` ${n._flow_id}{${n.value}}\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`:` ${n._flow_id}((${n.value}))\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:0,text:n.type=="IfStatement"?"🔷":"🔵"}}if(n.condition&&n.condition.value)n._flow_condition="|"+n.condition.value.replaceAll("|","|").replaceAll("[","⌈").replaceAll("]","⌋")+"|";_doBody(n,file)}else if(r.FlowFilter[n._flow_id]&&(n.type=="NewExpression"||n.type=="CallExpression")){if(n.type=="NewExpression"){r.FlowVarNew[node.value]=n.value;if(cls.value)r.UMLClass[cls.value][n._flow_id]=n;n._flow_str=` ${n._flow_id}[${n.value}]\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6,text:n.value}}else{if(n.callee.value==node.value){if(r.showMethod){n._flow_callee=n.value+"_"+cls.value}else{n._flow_callee=n.value}}else{n._flow_callee=n.callee.value}if(r.FlowNode[n._flow_id])n._flow_id=n._flow_callee+"_"+n._flow_id;n._flow_str=` ${n._flow_id}([${n.value}])\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6+d3config.fontsize*2,text:n.value+"()"}}r.Flow+=n._flow_str}else if(n.type=="Expression"){n._flow_id=node._flow_id;_doBody(n,file)}else if(n.type=="Variable"){n._flow_id=node._flow_id;if(!r.showMethod)traverseVariable(n,file);else{_doBody(n,file)}}else if(n.type=="BlockStatement"){n._flow_id=node._flow_id;_doBody(n,file)}r.FlowNode[n._flow_id]=n}}}function traverseVariable(variable,file){if(r.showMethod)return;_doBody(variable,file);function _doBody(node,file){if(!node.body)return;for(let n of node.body){n._file=file;n._flow_id=n.value+"_"+node._flow_id;n._flow_from=node._flow_id;if(r.FlowNode[n._flow_id])continue;r.FlowNode[n._flow_id]=n;if(r.FlowFilter[n._flow_id]&&(n.type=="NewExpression"||n.type=="CallExpression")){if(n.type=="NewExpression"){r.FlowVarNew[node.value]=n.value;n._flow_str=` ${n._flow_id}[${n.value}]\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6,text:n.value}}else{n._flow_str=` ${n._flow_id}([${n.value}])\nclick ${n._flow_id} "javascript:void(onFlowClick('${n._flow_id}','${file}'))"\n`;r.FDPNode[n._flow_id]={id:n._flow_id,w:n.value.length*d3config.fontsize/1.6+d3config.fontsize*2,text:n.value+"()"}}r.Flow+=n._flow_str}else if(n.type=="Expression"){n._flow_id=node._flow_id;_doBody(n,file)}}}}}function analysisD3(node,file){node.children=[];if(node.body&&node.body.length>0){for(let b of node.body){if(d3config.scastops[b.type]||d3config.scastops.all){node.children.push(b)}}}switch(node.type){case"top":node.name=file;node.value=file;break;case"ClassDefine":node.name=`[ ${node.value} ]`;break;case"InterfaceDefine":node.name=`( ${node.value} )`;break;case"MethodDefine":if(node.level&&level_symbol[node.level]){node.name=`${level_symbol[node.level]}${node.value}()`}else{node.name=`:${node.value}()`}break;case"FunctionDefine":node.name=`:${node.value}()`;break;case"PropertyDefine":if(node.level&&level_symbol[node.level]){node.name=`${level_symbol[node.level]}${node.value}`}else{node.name=`${node.value}`}break;case"NamespaceDefine":node.name=node.value+".namespace";break;case"NewExpression":node.name="( "+node.value+" )";break;case"CallExpression":node.name=node.value+"()";break;default:node.name=node.value}}var d3config={scastops:types,fontsize:14};function setD3Config(conf){d3config=conf}return{getAst:getAst,traverseAst:traverseAst,analysisMermaid:analysisMermaid,analysisD3:analysisD3,types:types,setD3Config:setD3Config}}();