🚀 add operator `^=` `&=` `|=`

fix bug of parsing expressions beginning with floater
This commit is contained in:
ValKmjolnir 2023-02-28 00:30:27 +08:00
parent 461e5ac647
commit e11793d340
14 changed files with 214 additions and 104 deletions

View File

@ -234,7 +234,7 @@ Bitwise operators `~` `|` `&` `^` have the same function as C/C++.
0x8^0x1; # xor
```
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
Operators `=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=` are used in assignment expressions.
```javascript
a=b=c=d=1;
@ -243,6 +243,10 @@ a-=1;
a*=1;
a/=1;
a~="string";
a^=0xff;
a&=0xca;
a|=0xba;
```
</details>

View File

@ -219,7 +219,7 @@ Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的
0x8^0x1; # 按位异或
```
赋值运算符`=` `+=` `-=` `*=` `/=` `~=`正如其名,用于进行赋值。
赋值运算符`=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=`正如其名,用于进行赋值。
```javascript
a=b=c=d=1;
@ -228,6 +228,10 @@ a-=1;
a*=1;
a/=1;
a~="string";
a^=0xff;
a&=0xca;
a|=0xba;
```
</details>

View File

@ -41,8 +41,17 @@ exprs::=
;
calculation::=
calculation '?' calculation ':' calculation
|or_expr
|calculation ('=' | '+=' | '-=' | '*=' | '/=' | '~=') calculation
|bitwise_or
|calculation ('=' | '+=' | '-=' | '*=' | '/=' | '~=' | '^=' | '&=' | '|=') calculation
;
bitwise_or::=
bitwise_xor '|' bitwise_xor
;
bitwise_xor::=
bitwise_and '^' bitwise_and
;
bitwise_and::=
or_expr '&' or_expr
;
or_expr::=
and_expr or and_expr

View File

@ -32,14 +32,14 @@ std::ostream& help(std::ostream& out) {
#endif
<<"\nnasal <option>\n"
<<"option:\n"
<<" -h, --help | get help.\n"
<<" -h, --help | get help.\n"
<<"\nnasal [option] <file> [argv]\n"
<<"option:\n"
<<" -a, --ast | view abstract syntax tree.\n"
<<" -c, --code | view bytecode.\n"
<<" -e, --exec | execute.\n"
<<" -t, --time | show execute time.\n"
<<" -d, --detail | get detail info.\n"
<<" -a, --ast | view abstract syntax tree.\n"
<<" -c, --code | view bytecode.\n"
<<" -e, --exec | execute.\n"
<<" -t, --time | show execute time.\n"
<<" -d, --detail | get detail info.\n"
<<" -dbg, --debug | debug mode.\n"
<<"file:\n"
<<" <filename> | execute file.\n"

View File

@ -35,6 +35,9 @@ enum ast_node:u32 {
ast_multeq, // *=
ast_diveq, // /=
ast_lnkeq, // ~=
ast_btandeq, // &=
ast_btoreq, // |=
ast_btxoreq, // ^=
ast_cmpeq, // ==
ast_neq, // !=
ast_less, // <
@ -85,56 +88,59 @@ const char* ast_name[]={
"HashMap",
"Vector",
"HashMapPair",
"IdentifierCallExpression",
"HashMapCallExpression",
"VectorCallExpression",
"FunctionCallExpression",
"IdentifierCall",
"HashMapCall",
"VectorCall",
"FunctionCall",
"SubVector",
"ParameterList",
"DefaultParameter",
"DynamicParameter",
"AndExpression",
"OrExpression",
"EqualExpression",
"AddEqualExpression",
"SubEqualExpression",
"MultEqualExpression",
"DivEqualExpression",
"LinkEqualExpression",
"CompareEqualExpression",
"NotEqualExpression",
"LessExpression",
"LessOrEqualExpression",
"GreatExpression",
"GreatOrEqualExpression",
"AddExpression",
"SubExpression",
"MultExpression",
"DivExpression",
"LinkExpression",
"NegativeExpression",
"LogicalNotExpression",
"BitwiseNotExpression",
"BitwiseOrExpression",
"BitwiseXorExpression",
"BitwiseAndExpression",
"TrinocularExpression",
"And",
"Or",
"Equal",
"AddEqual",
"SubEqual",
"MultEqual",
"DivEqual",
"LinkEqual",
"BitwiseAndEqual",
"BitwiseOrEqual",
"BitwiseXorEqual",
"CompareEqual",
"NotEqual",
"Less",
"LessOrEqual",
"Great",
"GreatOrEqual",
"Add",
"Sub",
"Mult",
"Div",
"Link",
"Negative",
"LogicalNot",
"BitwiseNot",
"BitwiseOr",
"BitwiseXor",
"BitwiseAnd",
"Trinocular",
"ForLoop",
"ForindexLoop",
"ForeachLoop",
"WhileLoop",
"Iterator",
"ConditionStatement",
"IfStatement",
"ElsifStatement",
"ElseStatement",
"Condition",
"If",
"Elsif",
"Else",
"LeftTuple",
"Tuple",
"Definition",
"MultipleAssignment",
"Continue",
"Break",
"ReturnStatement"
"Return"
};
class ast {

View File

@ -46,6 +46,9 @@ enum op_code_type:u8 {
op_muleq, // *=
op_diveq, // /=
op_lnkeq, // ~=
op_btandeq,// &=
op_btoreq, // |=
op_btxoreq,// ^=
op_addeqc, // += const
op_subeqc, // -= const
op_muleqc, // *= const
@ -100,17 +103,18 @@ const char* opname[]={
"mult ","div ","lnk ","addc ",
"subc ","multc ","divc ","lnkc ",
"addeq ","subeq ","muleq ","diveq ",
"lnkeq ","addeqc","subeqc","muleqc",
"diveqc","lnkeqc","meq ","eq ",
"neq ","less ","leq ","grt ",
"geq ","lessc ","leqc ","grtc ",
"geqc ","pop ","jmp ","jt ",
"jf ","cnt ","findx ","feach ",
"callg ","calll ","upval ","callv ",
"callvi","callh ","callfv","callfh",
"callb ","slcbeg","slcend","slc ",
"slc2 ","mcallg","mcalll","mupval",
"mcallv","mcallh","ret "
"lnkeq ","bandeq","boreq ","bxoreq",
"addeqc","subeqc","muleqc","diveqc",
"lnkeqc","meq ","eq ","neq ",
"less ","leq ","grt ","geq ",
"lessc ","leqc ","grtc ","geqc ",
"pop ","jmp ","jt ","jf ",
"cnt ","findx ","feach ","callg ",
"calll ","upval ","callv ","callvi",
"callh ","callfv","callfh","callb ",
"slcbeg","slcend","slc ","slc2 ",
"mcallg","mcalll","mupval","mcallv",
"mcallh","ret "
};
struct opcode {
@ -146,7 +150,8 @@ public:
<<opname[op]<<" "<<std::dec;
switch(op) {
case op_addeq: case op_subeq: case op_muleq: case op_diveq:
case op_lnkeq: case op_meq:
case op_lnkeq: case op_meq: case op_btandeq: case op_btoreq:
case op_btxoreq:
out<<std::hex<<"0x"<<num<<std::dec
<<" sp-"<<num;break;
case op_addeqc:case op_subeqc: case op_muleqc:case op_diveqc:
@ -801,8 +806,9 @@ void codegen::for_gen(const ast& node) {
case ast_multi_assign:multi_assign_gen(node[0]);break;
case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(node[0]);
if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) {
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) {
code.back().num=1;
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().num|=0x80000000;
@ -868,8 +874,9 @@ void codegen::for_gen(const ast& node) {
case ast_multi_assign:multi_assign_gen(node[2]);break;
case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(node[2]);
if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) {
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) {
code.back().num=1;
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().num|=0x80000000;
@ -1073,6 +1080,11 @@ void codegen::calc_gen(const ast& node) {
gen(op_lnkeqc,str_table[node[1].str()],node.line());
}
break;
case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(node[1]);
mcall(node[0]);
gen(node.type()-ast_btandeq+op_btandeq,0,node.line());
break;
case ast_or:or_gen(node);break;
case ast_and:and_gen(node);break;
// ast_add(33)~ast_link(37) op_add(18)~op_lnk(22)
@ -1194,8 +1206,9 @@ void codegen::block_gen(const ast& node) {
break;
case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(tmp);
if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) {
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) {
code.back().num=1;
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().num|=0x80000000;

View File

@ -211,17 +211,18 @@ void debugger::run(
&&mul, &&div, &&lnk, &&addc,
&&subc, &&mulc, &&divc, &&lnkc,
&&addeq, &&subeq, &&muleq, &&diveq,
&&lnkeq, &&addeqc, &&subeqc, &&muleqc,
&&diveqc, &&lnkeqc, &&meq, &&eq,
&&neq, &&less, &&leq, &&grt,
&&geq, &&lessc, &&leqc, &&grtc,
&&geqc, &&pop, &&jmp, &&jt,
&&jf, &&cnt, &&findex, &&feach,
&&callg, &&calll, &&upval, &&callv,
&&callvi, &&callh, &&callfv, &&callfh,
&&callb, &&slcbeg, &&slcend, &&slc,
&&slc2, &&mcallg, &&mcalll, &&mupval,
&&mcallv, &&mcallh, &&ret
&&lnkeq, &&bandeq, &&boreq, &&bxoreq,
&&addeqc, &&subeqc, &&muleqc, &&diveqc,
&&lnkeqc, &&meq, &&eq, &&neq,
&&less, &&leq, &&grt, &&geq,
&&lessc, &&leqc, &&grtc, &&geqc,
&&pop, &&jmp, &&jt, &&jf,
&&cnt, &&findex, &&feach, &&callg,
&&calll, &&upval, &&callv, &&callvi,
&&callh, &&callfv, &&callfh, &&callb,
&&slcbeg, &&slcend, &&slc, &&slc2,
&&mcallg, &&mcalll, &&mupval, &&mcallv,
&&mcallh, &&ret
};
std::vector<const void*> code;
for(auto& i:gen.codes()) {
@ -251,7 +252,9 @@ void debugger::run(
&debugger::o_divc, &debugger::o_lnkc,
&debugger::o_addeq, &debugger::o_subeq,
&debugger::o_muleq, &debugger::o_diveq,
&debugger::o_lnkeq, &debugger::o_addeqc,
&debugger::o_lnkeq, &debugger::o_bandeq,
&debugger::o_boreq, &debugger::o_bxoreq,
&debugger::o_addeqc,
&debugger::o_subeqc, &debugger::o_muleqc,
&debugger::o_diveqc, &debugger::o_lnkeqc,
&debugger::o_meq, &debugger::o_eq,
@ -344,6 +347,9 @@ subeq: dbg(o_subeq ,op_subeq );
muleq: dbg(o_muleq ,op_muleq );
diveq: dbg(o_diveq ,op_diveq );
lnkeq: dbg(o_lnkeq ,op_lnkeq );
bandeq: dbg(o_bandeq,op_btandeq);
boreq: dbg(o_boreq, op_btoreq);
bxoreq: dbg(o_bxoreq,op_btxoreq);
addeqc: dbg(o_addeqc,op_addeqc);
subeqc: dbg(o_subeqc,op_subeqc);
muleqc: dbg(o_muleqc,op_muleqc);

View File

@ -12,6 +12,7 @@
#define F_OK 0
#endif
#include "nasal.h"
#include "nasal_ast.h"
#include "nasal_lexer.h"
#include "nasal_parse.h"
@ -61,25 +62,28 @@ string linker::path(const ast& node) {
}
string fpath=".";
for(usize i=1;i<node.size();++i) {
#ifndef _WIN32
fpath+="/"+node[i].str();
#else
fpath+="\\"+node[i].str();
#endif
fpath+=(is_windows()? "\\":"/")+node[i].str();
}
return fpath+".nas";
}
string linker::findf(const string& fname) {
// first add file name itself into the file path
std::vector<string> fpath={fname};
// generate search path from environ path
for(auto&p:envpath) {
fpath.push_back(p+(is_windows()? "\\":"/")+fname);
}
// search file
for(auto& i:fpath) {
if (access(i.c_str(),F_OK)!=-1) {
return i;
}
}
// we will find lib.nas in nasal std directory
if (fname=="lib.nas") {
return is_windows()? findf("stl\\lib.nas"):findf("stl/lib.nas");
}

View File

@ -62,6 +62,9 @@ enum class tok:u32 {
multeq, // operator *=
diveq, // operator /=
lnkeq, // operator ~=
btandeq, // operator &=
btoreq, // operator |=
btxoreq, // operator ^=
cmpeq, // operator ==
neq, // operator !=
less, // operator <
@ -137,6 +140,9 @@ private:
{"*=" ,tok::multeq },
{"/=" ,tok::diveq },
{"~=" ,tok::lnkeq },
{"&=" ,tok::btandeq },
{"|=" ,tok::btoreq },
{"^=" ,tok::btxoreq },
{"==" ,tok::cmpeq },
{"!=" ,tok::neq },
{"<" ,tok::less },
@ -200,9 +206,8 @@ bool lexer::is_single_opr(char c) {
return (
c=='('||c==')'||c=='['||c==']'||
c=='{'||c=='}'||c==','||c==';'||
c=='|'||c==':'||c=='?'||c=='`'||
c=='&'||c=='@'||c=='%'||c=='$'||
c=='^'||c=='\\'
c==':'||c=='?'||c=='`'||c=='@'||
c=='%'||c=='$'||c=='\\'
);
}
@ -210,7 +215,7 @@ bool lexer::is_calc_opr(char c) {
return (
c=='='||c=='+'||c=='-'||c=='*'||
c=='!'||c=='/'||c=='<'||c=='>'||
c=='~'
c=='~'||c=='|'||c=='&'||c=='^'
);
}

View File

@ -15,14 +15,17 @@ void const_num(ast& root) {
auto& vec=root.child();
f64 res=0;
switch(root.type()) {
case ast_add: res=vec[0].num()+vec[1].num(); break;
case ast_sub: res=vec[0].num()-vec[1].num(); break;
case ast_mult:res=vec[0].num()*vec[1].num(); break;
case ast_div: res=vec[0].num()/vec[1].num(); break;
case ast_less:res=vec[0].num()<vec[1].num(); break;
case ast_leq: res=vec[0].num()<=vec[1].num();break;
case ast_grt: res=vec[0].num()>vec[1].num(); break;
case ast_geq: res=vec[0].num()>=vec[1].num();break;
case ast_add: res=vec[0].num()+vec[1].num(); break;
case ast_sub: res=vec[0].num()-vec[1].num(); break;
case ast_mult: res=vec[0].num()*vec[1].num(); break;
case ast_div: res=vec[0].num()/vec[1].num(); break;
case ast_less: res=vec[0].num()<vec[1].num(); break;
case ast_leq: res=vec[0].num()<=vec[1].num();break;
case ast_grt: res=vec[0].num()>vec[1].num(); break;
case ast_geq: res=vec[0].num()>=vec[1].num();break;
case ast_bitor: res=i32(vec[0].num())|i32(vec[1].num()); break;
case ast_bitxor: res=i32(vec[0].num())^i32(vec[1].num()); break;
case ast_bitand: res=i32(vec[0].num())&i32(vec[1].num()); break;
}
// inf and nan will cause number hashmap error in codegen
if (std::isinf(res) || std::isnan(res)) {
@ -52,7 +55,8 @@ void calc_const(ast& root) {
root.type()!=ast_mult && root.type()!=ast_div &&
root.type()!=ast_link && root.type()!=ast_less &&
root.type()!=ast_leq && root.type()!=ast_grt &&
root.type()!=ast_geq) {
root.type()!=ast_geq && root.type()!=ast_bitor &&
root.type()!=ast_bitxor && root.type()!=ast_bitand) {
return;
}
if (root.type()==ast_link &&
@ -63,6 +67,7 @@ void calc_const(ast& root) {
const_num(root);
}
}
void optimize(ast& root) {
for(auto& i:root.child()) {
calc_const(i);

View File

@ -96,6 +96,9 @@ private:
{tok::multeq ,"*=" },
{tok::diveq ,"/=" },
{tok::lnkeq ,"~=" },
{tok::btandeq ,"&=" },
{tok::btoreq ,"|=" },
{tok::btxoreq ,"^=" },
{tok::cmpeq ,"==" },
{tok::neq ,"!=" },
{tok::less ,"<" },
@ -464,8 +467,8 @@ ast parse::lcurve_expr() {
return definition();
return check_tuple()?multi_assgin():calc();
}
ast parse::expr()
{
ast parse::expr() {
tok type=toks[ptr].type;
if ((type==tok::brk || type==tok::cont) && !in_loop) {
die(thisline,thiscol,thislen,"must use break/continue in loops");
@ -484,6 +487,7 @@ ast parse::expr()
case tok::lbracket:
case tok::lbrace:
case tok::sub:
case tok::floater:
case tok::opnot: return calc(); break;
case tok::var: return definition(); break;
case tok::lcurve: return lcurve_expr(); break;
@ -548,6 +552,12 @@ ast parse::calc() {
match(toks[ptr].type);
tmp.add(calc());
node=std::move(tmp);
} else if (toks[ptr].type==tok::btandeq || toks[ptr].type==tok::btoreq || toks[ptr].type==tok::btxoreq) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,(u32)toks[ptr].type-(u32)tok::btandeq+ast_btandeq,toks[ptr].file);
tmp.add(std::move(node));
match(toks[ptr].type);
tmp.add(calc());
node=std::move(tmp);
}
return node;
}

View File

@ -88,6 +88,9 @@ protected:
void o_muleq();
void o_diveq();
void o_lnkeq();
void o_bandeq();
void o_boreq();
void o_bxoreq();
void o_addeqc();
void o_subeqc();
void o_muleqc();
@ -507,6 +510,11 @@ void vm::o_lnkc() {
top[0]=ngc.newstr(top[0].tostr()+cstr[imm[pc]]);
}
// top[0] stores the value of memr[0], to avoid being garbage-collected
// so when the calculation ends, top-=1, then top-=imm[pc]
// because this return value is meaningless if on stack when imm[pc]=1
// like this: func{a+=c;}(); the result of 'a+c' will no be used later, imm[pc]=1
// but if b+=a+=c; the result of 'a+c' will be used later, imm[pc]=0
#define op_calc_eq(type)\
top[-1]=memr[0]=var::num(memr[0].tonum() type top[-1].tonum());\
memr=nullptr;\
@ -522,6 +530,29 @@ void vm::o_lnkeq() {
top-=imm[pc]+1;
}
void vm::o_bandeq() {
top[-1]=memr[0]=var::num(i32(memr[0].tonum())&i32(top[-1].tonum()));
memr=nullptr;
top-=imm[pc]+1;
}
void vm::o_boreq() {
top[-1]=memr[0]=var::num(i32(memr[0].tonum())|i32(top[-1].tonum()));
memr=nullptr;
top-=imm[pc]+1;
}
void vm::o_bxoreq() {
top[-1]=memr[0]=var::num(i32(memr[0].tonum())^i32(top[-1].tonum()));
memr=nullptr;
top-=imm[pc]+1;
}
// top[0] stores the value of memr[0], to avoid being garbage-collected
// so when the calculation ends, top-=imm[pc]>>31
// because this return value is meaningless if on stack when imm[pc]>>31=1
// like this: func{a+=1;}(); the result of 'a+1' will no be used later, imm[pc]>>31=1
// but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0
#define op_calc_eq_const(type)\
top[0]=memr[0]=var::num(memr[0].tonum() type cnum[imm[pc]&0x7fffffff]);\
memr=nullptr;\
@ -1029,17 +1060,18 @@ void vm::run(
&&mul, &&div, &&lnk, &&addc,
&&subc, &&mulc, &&divc, &&lnkc,
&&addeq, &&subeq, &&muleq, &&diveq,
&&lnkeq, &&addeqc, &&subeqc, &&muleqc,
&&diveqc, &&lnkeqc, &&meq, &&eq,
&&neq, &&less, &&leq, &&grt,
&&geq, &&lessc, &&leqc, &&grtc,
&&geqc, &&pop, &&jmp, &&jt,
&&jf, &&cnt, &&findex, &&feach,
&&callg, &&calll, &&upval, &&callv,
&&callvi, &&callh, &&callfv, &&callfh,
&&callb, &&slcbeg, &&slcend, &&slc,
&&slc2, &&mcallg, &&mcalll, &&mupval,
&&mcallv, &&mcallh, &&ret
&&lnkeq, &&bandeq, &&boreq, &&bxoreq,
&&addeqc, &&subeqc, &&muleqc, &&diveqc,
&&lnkeqc, &&meq, &&eq, &&neq,
&&less, &&leq, &&grt, &&geq,
&&lessc, &&leqc, &&grtc, &&geqc,
&&pop, &&jmp, &&jt, &&jf,
&&cnt, &&findex, &&feach, &&callg,
&&calll, &&upval, &&callv, &&callvi,
&&callh, &&callfv, &&callfh, &&callb,
&&slcbeg, &&slcend, &&slc, &&slc2,
&&mcallg, &&mcalll, &&mupval, &&mcallv,
&&mcallh, &&ret
};
std::vector<const void*> code;
for(auto& i:gen.codes()) {
@ -1069,7 +1101,9 @@ void vm::run(
&vm::o_divc, &vm::o_lnkc,
&vm::o_addeq, &vm::o_subeq,
&vm::o_muleq, &vm::o_diveq,
&vm::o_lnkeq, &vm::o_addeqc,
&vm::o_lnkeq, &vm::o_bandeq,
&vm::o_boreq, &vm::o_bxoreq,
&vm::o_addeqc,
&vm::o_subeqc, &vm::o_muleqc,
&vm::o_diveqc, &vm::o_lnkeqc,
&vm::o_meq, &vm::o_eq,
@ -1162,6 +1196,9 @@ subeq: exec_nodie(o_subeq ); // -1
muleq: exec_nodie(o_muleq ); // -1
diveq: exec_nodie(o_diveq ); // -1
lnkeq: exec_nodie(o_lnkeq ); // -1
bandeq: exec_nodie(o_bandeq); // -1
boreq: exec_nodie(o_boreq ); // -1
bxoreq: exec_nodie(o_bxoreq); // -1
addeqc: exec_nodie(o_addeqc); // -0
subeqc: exec_nodie(o_subeqc); // -0
muleqc: exec_nodie(o_muleqc); // -0

View File

@ -222,4 +222,10 @@ for(var a=0;a<16;a+=1) {
}
}
}
}
for(var a=0;a<16;a+=1) {
for(var b=0;b<16;b+=1) {
var temp=b;
println("temp^=0x"~h[a]~" -> 0x",h[temp^=a]," temp&=0x"~h[a]~" -> 0x",h[temp&=a]," temp|=0x"~h[a]~" -> 0x",h[temp|=a]);
}
}

View File

@ -48,6 +48,7 @@ while(1){
var cmd=(os.platform()=="windows"?"":"./")~"nasal "~filename;
foreach(var i;args)
cmd~=" "~i;
println(os_time(),info_hd(),"\e[1mexecuting command \"",cmd,"\"\e[0m");
var ret=system(cmd);
if(ret!=0){
println(os_time(),err_hd(),"\e[1mprocess returned ",ret,"\e[0m");