From 4dc4c1d2b7ce1a59b519f84b4352d7f7355e0877 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Fri, 27 Dec 2024 19:21:07 +0800 Subject: [PATCH 01/12] :memo: fix typo --- doc/windows-build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/windows-build.md b/doc/windows-build.md index 665ba49..53fdbb7 100644 --- a/doc/windows-build.md +++ b/doc/windows-build.md @@ -10,7 +10,7 @@ Valid on powershell: mkdir cmake-windows-msvc cd cmake-windows-msvc cmake .. -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -MSbuild.exe nasal.sln /p:Configuration=Release /p:Platform=x64 +MSBuild.exe nasal.sln /p:Configuration=Release /p:Platform=x64 ``` ## MingW-W64 From 688fbe8c5dede479c5cab1b4cddba88024f5c3ca Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 1 Jan 2025 16:39:25 +0800 Subject: [PATCH 02/12] :art: formating --- src/nasal_vm.h | 135 ++++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 6221208..258c972 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -511,10 +511,10 @@ inline void vm::o_lnk() { // concat two vectors into one if (ctx.top[-1].is_vec() && ctx.top[0].is_vec()) { ngc.temp = ngc.alloc(vm_type::vm_vec); - for(auto i : ctx.top[-1].vec().elems) { + for(auto& i : ctx.top[-1].vec().elems) { ngc.temp.vec().elems.push_back(i); } - for(auto i : ctx.top[0].vec().elems) { + for(auto& i : ctx.top[0].vec().elems) { ngc.temp.vec().elems.push_back(i); } ctx.top[-1] = ngc.temp; @@ -523,17 +523,17 @@ inline void vm::o_lnk() { return; } // concat strings - ctx.top[-1] = ngc.newstr(ctx.top[-1].to_str()+ctx.top[0].to_str()); + ctx.top[-1] = ngc.newstr(ctx.top[-1].to_str() + ctx.top[0].to_str()); --ctx.top; } #define op_calc_const(type)\ ctx.top[0] = var::num(ctx.top[0].to_num() type const_number[imm[ctx.pc]]); -inline void vm::o_addc() {op_calc_const(+);} -inline void vm::o_subc() {op_calc_const(-);} -inline void vm::o_mulc() {op_calc_const(*);} -inline void vm::o_divc() {op_calc_const(/);} +inline void vm::o_addc() { op_calc_const(+); } +inline void vm::o_subc() { op_calc_const(-); } +inline void vm::o_mulc() { op_calc_const(*); } +inline void vm::o_divc() { op_calc_const(/); } inline void vm::o_lnkc() { ctx.top[0] = ngc.newstr(ctx.top[0].to_str() + const_string[imm[ctx.pc]]); } @@ -548,12 +548,12 @@ inline void vm::o_lnkc() { ctx.memr[0].to_num() type ctx.top[-1].to_num()\ );\ ctx.memr = nullptr;\ - ctx.top -= imm[ctx.pc]+1; + ctx.top -= imm[ctx.pc] + 1; -inline void vm::o_addeq() {op_calc_eq(+);} -inline void vm::o_subeq() {op_calc_eq(-);} -inline void vm::o_muleq() {op_calc_eq(*);} -inline void vm::o_diveq() {op_calc_eq(/);} +inline void vm::o_addeq() { op_calc_eq(+); } +inline void vm::o_subeq() { op_calc_eq(-); } +inline void vm::o_muleq() { op_calc_eq(*); } +inline void vm::o_diveq() { op_calc_eq(/); } inline void vm::o_lnkeq() { // concat two vectors into one if (ctx.top[-1].is_vec() && ctx.memr[0].is_vec()) { @@ -572,7 +572,7 @@ inline void vm::o_lnkeq() { } ctx.top[-1] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].to_str()+ctx.top[-1].to_str() + ctx.memr[0].to_str() + ctx.top[-1].to_str() ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc] + 1; @@ -616,13 +616,13 @@ inline void vm::o_bxoreq() { );\ ctx.memr = nullptr; -inline void vm::o_addeqc() {op_calc_eq_const(+);} -inline void vm::o_subeqc() {op_calc_eq_const(-);} -inline void vm::o_muleqc() {op_calc_eq_const(*);} -inline void vm::o_diveqc() {op_calc_eq_const(/);} +inline void vm::o_addeqc() { op_calc_eq_const(+); } +inline void vm::o_subeqc() { op_calc_eq_const(-); } +inline void vm::o_muleqc() { op_calc_eq_const(*); } +inline void vm::o_diveqc() { op_calc_eq_const(/); } inline void vm::o_lnkeqc() { ctx.top[0] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].to_str()+const_string[imm[ctx.pc]] + ctx.memr[0].to_str() + const_string[imm[ctx.pc]] ); ctx.memr = nullptr; } @@ -634,13 +634,13 @@ inline void vm::o_lnkeqc() { ctx.memr = nullptr;\ --ctx.top; -inline void vm::o_addecp() {op_calc_eq_const_and_pop(+);} -inline void vm::o_subecp() {op_calc_eq_const_and_pop(-);} -inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);} -inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);} +inline void vm::o_addecp() { op_calc_eq_const_and_pop(+); } +inline void vm::o_subecp() { op_calc_eq_const_and_pop(-); } +inline void vm::o_mulecp() { op_calc_eq_const_and_pop(*); } +inline void vm::o_divecp() { op_calc_eq_const_and_pop(/); } inline void vm::o_lnkecp() { ctx.top[0] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].to_str()+const_string[imm[ctx.pc]] + ctx.memr[0].to_str() + const_string[imm[ctx.pc]] ); ctx.memr = nullptr; --ctx.top; @@ -663,12 +663,12 @@ inline void vm::o_eq() { if (val1.is_nil() && val2.is_nil()) { ctx.top[0] = one; } else if (val1.is_str() && val2.is_str()) { - ctx.top[0] = (val1.str()==val2.str())? one:zero; + ctx.top[0] = (val1.str()==val2.str())? one : zero; } else if ((val1.is_num() || val2.is_num()) && !val1.is_nil() && !val2.is_nil()) { - ctx.top[0] = (val1.to_num()==val2.to_num())? one:zero; + ctx.top[0] = (val1.to_num()==val2.to_num())? one : zero; } else { - ctx.top[0] = (val1==val2)? one:zero; + ctx.top[0] = (val1==val2)? one : zero; } } @@ -678,59 +678,59 @@ inline void vm::o_neq() { if (val1.is_nil() && val2.is_nil()) { ctx.top[0] = zero; } else if (val1.is_str() && val2.is_str()) { - ctx.top[0] = (val1.str()!=val2.str())? one:zero; + ctx.top[0] = (val1.str()!=val2.str())? one : zero; } else if ((val1.is_num() || val2.is_num()) && !val1.is_nil() && !val2.is_nil()) { - ctx.top[0] = (val1.to_num()!=val2.to_num())? one:zero; + ctx.top[0] = (val1.to_num()!=val2.to_num())? one : zero; } else { - ctx.top[0] = (val1!=val2)? one:zero; + ctx.top[0] = (val1!=val2)? one : zero; } } #define op_cmp(type)\ --ctx.top;\ - ctx.top[0] = (ctx.top[0].to_num() type ctx.top[1].to_num())? one:zero; + ctx.top[0] = (ctx.top[0].to_num() type ctx.top[1].to_num())? one : zero; -inline void vm::o_less() {op_cmp(<);} -inline void vm::o_leq() {op_cmp(<=);} -inline void vm::o_grt() {op_cmp(>);} -inline void vm::o_geq() {op_cmp(>=);} +inline void vm::o_less() { op_cmp(<); } +inline void vm::o_leq() { op_cmp(<=); } +inline void vm::o_grt() { op_cmp(>); } +inline void vm::o_geq() { op_cmp(>=); } #define op_cmp_const(type)\ - ctx.top[0] = (ctx.top[0].to_num() type const_number[imm[ctx.pc]])? one:zero; + ctx.top[0] = (ctx.top[0].to_num() type const_number[imm[ctx.pc]])? one : zero; -inline void vm::o_lessc() {op_cmp_const(<);} -inline void vm::o_leqc() {op_cmp_const(<=);} -inline void vm::o_grtc() {op_cmp_const(>);} -inline void vm::o_geqc() {op_cmp_const(>=);} +inline void vm::o_lessc() { op_cmp_const(<); } +inline void vm::o_leqc() { op_cmp_const(<=); } +inline void vm::o_grtc() { op_cmp_const(>); } +inline void vm::o_geqc() { op_cmp_const(>=); } inline void vm::o_pop() { --ctx.top; } inline void vm::o_jmp() { - ctx.pc = imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc] - 1; } inline void vm::o_jt() { // jump true needs to reserve the result on stack // because conditional expression in nasal has return value if (boolify(ctx.top[0])) { - ctx.pc = imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc] - 1; } } inline void vm::o_jf() { // jump false doesn't need to reserve result if (!boolify(ctx.top[0])) { - ctx.pc = imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc] - 1; } --ctx.top; } inline void vm::o_cnt() { if (!ctx.top[0].is_vec()) { - die("must use vector in forindex/foreach but get "+ + die("must use vector in forindex/foreach but get " + type_name_string(ctx.top[0]) ); return; @@ -768,8 +768,8 @@ inline void vm::o_calll() { inline void vm::o_upval() { (++ctx.top)[0] = ctx.funcr.func() - .upval[(imm[ctx.pc]>>16)&0xffff] - .upval()[imm[ctx.pc]&0xffff]; + .upval[(imm[ctx.pc] >> 16) & 0xffff] + .upval()[imm[ctx.pc] & 0xffff]; } inline void vm::o_callv() { @@ -783,7 +783,7 @@ inline void vm::o_callv() { } } else if (vec.is_hash()) { if (!val.is_str()) { - die("must use string as the key but get "+type_name_string(val)); + die("must use string as the key but get " + type_name_string(val)); return; } ctx.top[0] = vec.hash().get_value(val.str()); @@ -802,20 +802,20 @@ inline void vm::o_callv() { return; } ctx.top[0] = var::num( - static_cast(static_cast(str[num>=0? num:num+len])) + static_cast(static_cast(str[num>=0? num : num + len])) ); } else if (vec.is_map()) { if (!val.is_str()) { - die("must use string as the key but get "+type_name_string(val)); + die("must use string as the key but get " + type_name_string(val)); return; } ctx.top[0] = vec.map().get_value(val.str()); if (ctx.top[0].is_none()) { - die("cannot find symbol \""+val.str()+"\""); + die("cannot find symbol \"" + val.str() + "\""); return; } } else { - die("must call a vector/hash/string but get "+type_name_string(vec)); + die("must call a vector/hash/string but get " + type_name_string(vec)); return; } } @@ -823,7 +823,7 @@ inline void vm::o_callv() { inline void vm::o_callvi() { var val = ctx.top[0]; if (!val.is_vec()) { - die("must use a vector but get "+type_name_string(val)); + die("must use a vector but get " + type_name_string(val)); return; } // cannot use operator[], because this may cause overflow @@ -837,7 +837,7 @@ inline void vm::o_callvi() { inline void vm::o_callh() { var val = ctx.top[0]; if (!val.is_hash() && !val.is_map()) { - die("must call a hash but get "+type_name_string(val)); + die("must call a hash but get " + type_name_string(val)); return; } @@ -847,21 +847,26 @@ inline void vm::o_callh() { } else { ctx.top[0] = val.map().get_value(str); } + + // report key not found if get_value returns none if (ctx.top[0].is_none()) { - val.is_hash()? - die(report_key_not_found(str, val.hash())): - die("cannot find symbol \"" + str + "\""); + val.is_hash() + ? die(report_key_not_found(str, val.hash())) + : die("cannot find symbol \"" + str + "\""); return; - } else if (ctx.top[0].is_func()) { + } + + // if get function from hash, set 'me' + if (ctx.top[0].is_func() && val.is_hash()) { ctx.top[0].func().local[0] = val; // 'me' } } inline void vm::o_callfv() { const auto argc = imm[ctx.pc]; // arguments counter - var* local = ctx.top-argc+1; // arguments begin address + var* local = ctx.top - argc + 1; // arguments begin address if (!local[-1].is_func()) { - die("must call a function but get "+type_name_string(local[-1])); + die("must call a function but get " + type_name_string(local[-1])); return; } const auto& func = local[-1].func(); @@ -904,7 +909,7 @@ inline void vm::o_callfv() { // then all the available values the vector needs // are all outside the stack top and may be // collected incorrectly - ctx.top = local+func.local_size; + ctx.top = local + func.local_size; // use (std::min) to avoid compilation error in MSVC // MSVC windows.h uses macro std::min @@ -917,12 +922,14 @@ inline void vm::o_callfv() { local[0] = func.local[0]; // load "me" // load local scope & default arguments - for(u64 i = min_size+1; i=0? - parameter_size+1:func.local_size-1] = dynamic; + local[func.dynamic_parameter_index >= 0 + ? parameter_size + 1 + : func.local_size - 1] = dynamic; ctx.top[0] = ctx.upvalr; (++ctx.top)[0] = var::addr(ctx.localr); @@ -935,7 +942,7 @@ inline void vm::o_callfv() { inline void vm::o_callfh() { const auto& hash = ctx.top[0].hash().elems; if (!ctx.top[-1].is_func()) { - die("must call a function but get "+type_name_string(ctx.top[-1])); + die("must call a function but get " + type_name_string(ctx.top[-1])); return; } const auto& func = ctx.top[-1].func(); @@ -1013,7 +1020,7 @@ inline void vm::o_slcbeg() { // +--------------+ (++ctx.top)[0] = ngc.alloc(vm_type::vm_vec); if (!ctx.top[-1].is_vec()) { - die("must slice a vector but get "+type_name_string(ctx.top[-1])); + die("must slice a vector but get " + type_name_string(ctx.top[-1])); return; } } From fd93fbafdf94f4d06f25e170d4737aea61bcb558 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 1 Jan 2025 16:56:11 +0800 Subject: [PATCH 03/12] :art: formating console3D test --- test/burningship.nas | 4 +- test/console3D.nas | 218 +++++++++++++++++++++++++------------------ 2 files changed, 130 insertions(+), 92 deletions(-) diff --git a/test/burningship.nas b/test/burningship.nas index 357b131..277396c 100644 --- a/test/burningship.nas +++ b/test/burningship.nas @@ -16,8 +16,8 @@ var ppm = func(filename, width, height, RGB) { io.close(fd); } -var width = 1920; -var height = 1080; +var width = 1920 * 2; +var height = 1080 * 2; var bar = (os.platform()=="windows")? process_bar.bar(front:"sharp", back:"point", sep:"line", length:50): process_bar.high_resolution_bar(50); diff --git a/test/console3D.nas b/test/console3D.nas index f4a2afa..abf4933 100644 --- a/test/console3D.nas +++ b/test/console3D.nas @@ -31,7 +31,8 @@ func() { runtime.gc.extend("vec", 8); }(); -var (max,min,sqrt,sin,cos,abs)=( +# alias +var (max, min, sqrt, sin, cos, abs) = ( math.max, math.min, math.sqrt, @@ -40,12 +41,12 @@ var (max,min,sqrt,sin,cos,abs)=( math.abs ); -var (vec2,vec3)=( +var (vec2, vec3) = ( libmat.vec2.new, libmat.vec3.new ); -var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=( +var (vec2add, vec2sub, vec2mul, vec2div, vec2len) = ( libmat.vec2.add, libmat.vec2.sub, libmat.vec2.mul, @@ -53,7 +54,7 @@ var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=( libmat.vec2.len ); -var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=( +var (vec3add, vec3sub, vec3mul, vec3div, vec3neg, vec3norm, vec3len, vec3dot) = ( libmat.vec3.add, libmat.vec3.sub, libmat.vec3.mul, @@ -64,116 +65,147 @@ var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=( libmat.vec3.dot ); -var (rotateX,rotateY,rotateZ)=( +var (rotateX, rotateY, rotateZ) = ( libmat.vec3.rx, libmat.vec3.ry, libmat.vec3.rz, ); var use_raw = func() { - vec2 = func(x,y) {return [x,y];} - vec2add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1]];} - vec2sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1]];} - vec2mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1]];} - vec2div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1]];} - vec3 = func(x,y,z) {return [x,y,z];} - vec3add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];} - vec3sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];} - vec3mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];} - vec3div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];} - vec3neg = func(v) {return [-v[0],-v[1],-v[2]];} + vec2 = func(x, y) {return [x,y];} + vec2add = func(v1, v2) {return [v1[0]+v2[0],v1[1]+v2[1]];} + vec2sub = func(v1, v2) {return [v1[0]-v2[0],v1[1]-v2[1]];} + vec2mul = func(v1, v2) {return [v1[0]*v2[0],v1[1]*v2[1]];} + vec2div = func(v1, v2) {return [v1[0]/v2[0],v1[1]/v2[1]];} vec2len = func(v) {var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);} + + vec3 = func(x, y, z) {return [x,y,z];} + vec3add = func(v1, v2) {return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];} + vec3sub = func(v1, v2) {return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];} + vec3mul = func(v1, v2) {return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];} + vec3div = func(v1, v2) {return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];} + vec3neg = func(v) {return [-v[0],-v[1],-v[2]];} vec3len = func(v) {var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);} vec3norm = func(v) {var t=vec3len(v); return vec3div(v,[t,t,t]);} - vec3dot = func(a,b) {return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];} - rotateX = func(a,angle) {return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];} - rotateY = func(a,angle) {return [a[0]*cos(angle)-a[2]*sin(angle),a[1],a[0]*sin(angle)+a[2]*cos(angle)];} - rotateZ = func(a,angle) {return [a[0]*cos(angle)-a[1]*sin(angle),a[0]*sin(angle)+a[1]*cos(angle),a[2]];} + vec3dot = func(a, b) { + return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; + } + + rotateX = func(a, angle) { + return [ + a[0], + a[2] * sin(angle) + a[1] * cos(angle), + a[2] * cos(angle) - a[1] * sin(angle) + ]; + } + rotateY = func(a, angle) { + return [ + a[0] * cos(angle) - a[2] * sin(angle), + a[1], + a[0] * sin(angle) + a[2] * cos(angle) + ]; + } + rotateZ = func(a, angle) { + return [ + a[0] * cos(angle) - a[1] * sin(angle), + a[0] * sin(angle) + a[1] * cos(angle), + a[2] + ]; + } } -var clamp = func(value,_min,_max) { - return max(min(value,_max),_min); +var clamp = func(value, _min, _max) { + return max(min(value, _max), _min); } var sign = func(a) { - return (0edge; +var step = func(edge, x) { + return x > edge; } var vec3abs = func(v) { - return [abs(v[0]),abs(v[1]),abs(v[2])]; + return [abs(v[0]), abs(v[1]), abs(v[2])]; } var vec3sign = func(v) { - return [sign(v[0]),sign(v[1]),sign(v[2])]; + return [sign(v[0]), sign(v[1]), sign(v[2])]; } -var vec3step = func(edge,v) { - return [step(edge[0],v[0]),step(edge[1],v[1]),step(edge[2],v[2])]; +var vec3step = func(edge, v) { + return [ + step(edge[0], v[0]), + step(edge[1], v[1]), + step(edge[2], v[2]) + ]; } -var vec3reflect = func(rd,n) { - var d=vec3dot(n,rd); - return vec3sub(rd,vec3mul(n,vec3mul([2,2,2],[d,d,d]))); +var vec3reflect = func(rd, n) { + var d = vec3dot(n, rd); + return vec3sub(rd, vec3mul(n, vec3mul([2, 2, 2], [d, d, d]))); } -var sphere = func(ro,rd,r) { - var b=vec3dot(ro,rd); - var c=vec3dot(ro,ro)-r*r; - var h=b*b-c; - if (h<0.0) return [-1.0,-1.0]; - h=sqrt(h); - return [-b-h,-b+h]; +var sphere = func(ro, rd, r) { + var b = vec3dot(ro, rd); + var c = vec3dot(ro, ro) - r * r; + var h = b * b - c; + if (h < 0.0) + return [-1.0, -1.0]; + h = sqrt(h); + return [-b - h, -b + h]; } -var box = func(ro,rd,boxSize,outNormal) { - var m=vec3div([1.0,1.0,1.0],rd); - var n=vec3mul(m,ro); - var k=vec3mul(vec3abs(m),boxSize); - var t1=vec3sub(vec3neg(n),k); - var t2=vec3add(vec3neg(n),k); - var tN=max(max(t1[0],t1[1]),t1[2]); - var tF=min(min(t2[0],t2[1]),t2[2]); - if (tN>tF or tF<0.0) return [-1.0,-1.0]; - var yzx=[t1[1],t1[2],t1[0]]; - var zxy=[t1[2],t1[0],t1[1]]; - var tmp=vec3mul(vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx,t1)),vec3step(zxy,t1)); - outNormal[0]=tmp[0]; - outNormal[1]=tmp[1]; - outNormal[2]=tmp[2]; +var box = func(ro, rd, boxSize, outNormal) { + var m = vec3div([1.0, 1.0, 1.0], rd); + var n = vec3mul(m, ro); + var k = vec3mul(vec3abs(m), boxSize); + var t1 = vec3sub(vec3neg(n), k); + var t2 = vec3add(vec3neg(n), k); + var tN = max(max(t1[0], t1[1]), t1[2]); + var tF = min(min(t2[0], t2[1]), t2[2]); + if (tN>tF or tF<0.0) + return [-1.0, -1.0]; + var yzx = [t1[1], t1[2], t1[0]]; + var zxy = [t1[2], t1[0], t1[1]]; + var tmp = vec3mul( + vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx, t1)), + vec3step(zxy, t1) + ); + outNormal[0] = tmp[0]; + outNormal[1] = tmp[1]; + outNormal[2] = tmp[2]; return [tN, tF]; } -var plane = func(ro,rd,p,w) { - return -(vec3dot(ro,p)+w)/vec3dot(rd,p); +var plane = func(ro, rd, p, w) { + return -(vec3dot(ro, p) + w) / vec3dot(rd, p); } var main = func(frame) { - var height=15*2; - var width=int(height*1/0.618)*2; + var height = 15*2; + var width = int(height*1/0.618)*2; - var aspect=width/height; - var pixelAspect=11.0/24.0; + var aspect = width/height; + var pixelAspect = 11.0/24.0; - var gradient=split(""," .:!/r(l1Z4H9W8$"); - var gradientSize=size(gradient)-1; + var gradient = split("", " .:!/r(l1Z4H9W8$"); + var gradientSize = size(gradient)-1; - var screen=[]; - setsize(screen,width*height); + var screen = []; + setsize(screen, width*height); - var light=vec3norm([-0.5,0.5,-1.0]); - var spherePos=[0,3,0]; - var vec2_2_2=[2,2]; - var vec2_1_1=[1,1]; - var vec3_000=[0,0,0]; - var vec3_00n1=[0,0,-1]; - var vec3_111=[1,1,1]; + var light = vec3norm([-0.5, 0.5, -1.0]); + var spherePos = [0, 3, 0]; + var vec2_2_2 = [2, 2]; + var vec2_1_1 = [1, 1]; + var vec3_000 = [0, 0, 0]; + var vec3_00n1 = [0, 0, -1]; + var vec3_111 = [1, 1, 1]; print("\e[2J"); - var stamp=maketimestamp(); - for(var t=0;t Date: Wed, 1 Jan 2025 18:28:58 +0800 Subject: [PATCH 04/12] :art: dump gc time occupation --- makefile | 10 +++++----- src/main.cpp | 9 ++++++++- src/nasal_gc.h | 6 ++++++ src/nasal_vm.cpp | 23 +++++++++++++++++------ src/nasal_vm.h | 4 ++++ std/argparse.nas | 2 +- std/lib.nas | 2 +- test/feigenbaum.nas | 19 +++++++++++-------- test/mandelbrot.nas | 31 ++++++++++++++++--------------- test/mandelbrotset.nas | 4 ++-- 10 files changed, 71 insertions(+), 39 deletions(-) diff --git a/makefile b/makefile index 4482512..fb2f959 100644 --- a/makefile +++ b/makefile @@ -333,10 +333,10 @@ test: @ ./nasal -t -d test/regex_test.nas @ ./nasal -t -d test/replace_test.nas @ ./nasal -e test/scalar.nas hello world - @ ./nasal test/subprocess_test.nas - @ ./nasal -e test/trait.nas + @ ./nasal -t test/subprocess_test.nas + @ ./nasal -t test/trait.nas @ ./nasal -t -d test/turingmachine.nas - @ ./nasal -d test/wavecollapse.nas - @ ./nasal -d test/wavecity.nas - @ ./nasal test/word_collector.nas test/md5compare.nas + @ ./nasal -t -d test/wavecollapse.nas + @ ./nasal -t -d test/wavecity.nas + @ ./nasal -t test/word_collector.nas test/md5compare.nas @ ./nasal -t -d test/ycombinator.nas diff --git a/src/main.cpp b/src/main.cpp index aac6c26..3e0a4ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -121,6 +121,7 @@ void execute(const nasal::cli::cli_config& config) { // run const auto start = clk::now(); + double gc_time_ms = 0.0; if (config.has(option::cli_debug_mode)) { auto debugger = std::make_unique(); debugger->run( @@ -130,6 +131,7 @@ void execute(const nasal::cli::cli_config& config) { config.has(option::cli_profile), config.has(option::cli_profile_all) ); + gc_time_ms = debugger->get_gc_time_ms(); } else if (config.has(option::cli_show_execute_time) || config.has(option::cli_detail_info) || config.has(option::cli_limit_mode) || @@ -138,13 +140,18 @@ void execute(const nasal::cli::cli_config& config) { runtime->set_detail_report_info(config.has(option::cli_detail_info)); runtime->set_limit_mode_flag(config.has(option::cli_limit_mode)); runtime->run(gen, ld, config.nasal_vm_args); + gc_time_ms = runtime->get_gc_time_ms(); } // get running time const auto end = clk::now(); if (config.has(option::cli_show_execute_time)) { + double execute_time_sec = static_cast((end - start).count())/den; + double gc_time_sec = gc_time_ms / 1000.0; std::clog << "process exited after "; - std::clog << static_cast((end-start).count())/den << "s.\n\n"; + std::clog << execute_time_sec << "s, gc time: "; + std::clog << gc_time_sec << "s ("; + std::clog << gc_time_sec / execute_time_sec * 100.0 << "%)\n\n"; } } diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 5312d60..4827608 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -94,6 +94,12 @@ public: void context_change(nas_co*); void context_reserve(); +public: + double get_gc_time_ms() const { + const auto den = std::chrono::high_resolution_clock::duration::period::den; + return worktime * 1.0 / den * 1000.0; + } + public: var newstr(char c) { var s = alloc(vm_type::vm_str); diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 3a57ec4..c04c7ae 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -226,7 +226,7 @@ void vm::function_call_trace() { std::stack callsite; // load call trace - for(var* i = bottom; i<=top; ++i) { + for(var* i = bottom; i <= top; ++i) { // i-1 is the callsite program counter of this function if (i->is_addr() && i+2<=top && (i+1)->is_ret() && (i+1)->ret()>0 && @@ -238,7 +238,7 @@ void vm::function_call_trace() { // another condition may exist // have ret pc on stack, but no function at the top of the ret pc - for(var * i = top; i>=bottom; --i) { + for(var * i = top; i >= bottom; --i) { if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) || (i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) { functions.push(&ctx.funcr.func()); @@ -254,7 +254,7 @@ void vm::function_call_trace() { std::clog << "\ncall trace "; std::clog << (ngc.cort? "(coroutine)":"(main)") << "\n"; - std::clog << " crash occurred in\n "; + std::clog << " crash occurred at\n "; function_detail_info(ctx.funcr.func()); std::clog << " at " << files[bytecode[ctx.pc].fidx] << ":"; std::clog << bytecode[ctx.pc].line << "\n"; @@ -325,7 +325,7 @@ void vm::trace_back() { // the first called place has no same calls } -void vm::stack_info(const u64 limit = 16) { +void vm::stack_info(const u64 limit) { var* top = ctx.top; var* bottom = ctx.stack; const auto stack_address = reinterpret_cast(bottom); @@ -525,8 +525,16 @@ std::string vm::type_name_string(const var& value) const { void vm::die(const std::string& str) { std::cerr << "[vm] error: " << str << "\n"; function_call_trace(); - trace_back(); - stack_info(); + + // trace back contains bytecode info, dump in verbose mode + if (verbose) { + trace_back(); + } + + // verbose will dump more values on stack + if (verbose) { + stack_info(64); + } // show verbose crash info if (verbose) { @@ -534,6 +542,9 @@ void vm::die(const std::string& str) { } if (!ngc.cort) { + if (!verbose) { + std::cerr << "\n[vm] use <-d> for detailed crash info.\n\n"; + } // in main context, exit directly std::exit(1); } diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 258c972..62c1f87 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -318,6 +318,10 @@ public: void set_limit_mode_flag(bool flag) { flag_limited_mode = flag; } + + auto get_gc_time_ms() const { + return ngc.get_gc_time_ms(); + } }; inline bool vm::boolify(const var& val) { diff --git a/std/argparse.nas b/std/argparse.nas index a183329..507b7a2 100644 --- a/std/argparse.nas +++ b/std/argparse.nas @@ -151,7 +151,7 @@ var _parse = func(parser, args, result_hash) { return; } -var _add_command = func(parser, long, short, help, need_arg , need_nargs) { +var _add_command = func(parser, long, short, help, need_arg, need_nargs) { var new_command = { full_name: long, short_name: short, diff --git a/std/lib.nas b/std/lib.nas index e4b556a..da1eec6 100644 --- a/std/lib.nas +++ b/std/lib.nas @@ -380,7 +380,7 @@ var bind = func(function, locals, outer_scope = nil) { die("this runtime does not support bind"); } -var call = func(function ,args = nil, _me = nil, locals = nil, error = nil) { +var call = func(function, args = nil, _me = nil, locals = nil, error = nil) { die("this runtime does not support call"); } diff --git a/test/feigenbaum.nas b/test/feigenbaum.nas index d56d315..811f135 100644 --- a/test/feigenbaum.nas +++ b/test/feigenbaum.nas @@ -16,25 +16,29 @@ var ppm = func(filename, width, height, RGB) { io.close(fd); } -var width = 1920; -var height = 1080; +var width = 1920 * 2; +var height = 1080 * 2; var bar = (os.platform()=="windows")? process_bar.bar(front:"sharp", back:"point", sep:"line", length:50): process_bar.high_resolution_bar(50); +var abs = math.abs; # alias var RGB = func(h, w) { var r = 2+w*2/width; var x = (height-h)/height; - var res = 0; + var (R, G, B) = (0, 0, 0); + var tmp = 0.5; for(var i = 0; i<50; i+=1) { tmp = r*tmp*(1-tmp); } - for(var i = 0; i<100; i+=1) { + for(var i = 0; i<150; i+=1) { tmp = r*tmp*(1-tmp); - if (math.abs(tmp-x)<0.001) { - res = 255; + if (abs(tmp-x)<0.0005) { + R = int(255*(150 - i)/150); + G = int(255*(150 - i)/150); + B = 255; break; } } @@ -44,8 +48,7 @@ var RGB = func(h, w) { print(bar.bar(progress), " ", progress*100, "% \r"); } - var c = char(res); - return c~c~c; + return char(R) ~ char(G) ~ char(B); } ppm("feigenbaum.ppm", width, height, RGB); diff --git a/test/mandelbrot.nas b/test/mandelbrot.nas index 59722e3..1e712d9 100644 --- a/test/mandelbrot.nas +++ b/test/mandelbrot.nas @@ -1,22 +1,23 @@ -var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,""); -var (yDel,xDel)=(yMax-yMin,xMax-xMin); -for(var yPixel=0;yPixel<24;yPixel+=1) { - var y=(yPixel/24)*yDel+yMin; - for(var xPixel=0;xPixel<80;xPixel+=1) { - var x=(xPixel/80)*xDel+xMin; - var pixel=" "; - var (x0,y0)=(x,y); - for(var iter=0;iter<80;iter+=1) { - var x1=(x0*x0)-(y0*y0)+x; - var y1=2*x0*y0+y; - (x0,y0)=(x1,y1); +var (yMin, yMax, xMin, xMax, line) = (-0.2, 0.2, -1.5, -1.0, ""); +var (yDel, xDel) = (yMax-yMin, xMax-xMin); +for(var yPixel = 0; yPixel < 24; yPixel += 1) { + var y = (yPixel/24)*yDel+yMin; + for(var xPixel = 0; xPixel < 80; xPixel += 1) { + var x = (xPixel/80)*xDel+xMin; + var pixel = " "; + var (x0, y0) = (x, y); + for(var iter = 0; iter < 100; iter += 1) { + var x1 = (x0*x0)-(y0*y0)+x; + var y1 = 2*x0*y0+y; + (x0, y0) = (x1, y1); if ((x0*x0)+(y0*y0)>4) { - pixel=chr(" .:;+=xX$&"[iter/8]); + pixel = chr(" .:;+=xX$&"[iter/8]); break; } } - line~=pixel; + line ~= pixel; } - line~='\n'; + line ~= '\n'; } + print(line); \ No newline at end of file diff --git a/test/mandelbrotset.nas b/test/mandelbrotset.nas index c4573bc..064d3c8 100644 --- a/test/mandelbrotset.nas +++ b/test/mandelbrotset.nas @@ -15,8 +15,8 @@ var ppm = func(filename, width, height, RGB) { io.close(fd); } -var width = 1920; -var height = 1080; +var width = 1920 * 2; +var height = 1080 * 2; var bar = (os.platform()=="windows")? process_bar.bar(front:"sharp", back:"point", sep:"line", length:50): process_bar.high_resolution_bar(50); From 030a3ad920a04425f99c3da48f29a1c1000b9270 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 1 Jan 2025 18:35:57 +0800 Subject: [PATCH 05/12] :memo: remove -fPIC if using MSVC --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40d3f42..1cb6a3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,11 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall") -add_compile_options(-fPIC) +# MSVC does not need -fPIC +if (NOT MSVC) + add_compile_options(-fPIC) +endif() + # MSVC needs this command option to really enable utf-8 output if (MSVC) add_compile_options(/utf-8) @@ -19,9 +23,6 @@ if (APPLE) add_compile_options(-mmacosx-version-min=10.15) endif() -# generate release executables -set(CMAKE_BUILD_TYPE "Release") - # build nasal used object set(NASAL_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/cli/cli.cpp From 77ec4b0d7c8e554084b4db5ce168134de4cf327a Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Fri, 3 Jan 2025 01:03:13 +0800 Subject: [PATCH 06/12] :bug: add dylib find rule on mac --- src/nasal_type.cpp | 28 +++------------ src/nasal_type.h | 26 +++++++++++--- src/nasal_vm.h | 24 ++++++------- src/natives/dylib_lib.cpp | 71 +++++++++++++++++++++++++++------------ src/natives/dylib_lib.h | 2 ++ 5 files changed, 90 insertions(+), 61 deletions(-) diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 8a38b11..561f68c 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -6,22 +6,6 @@ namespace nasal { -var nas_vec::get_value(const i32 index) { - i32 size = elems.size(); - if (index<-size || index>=size) { - return var::none(); - } - return elems[index>=0? index:index+size]; -} - -var* nas_vec::get_memory(const i32 index) { - i32 size = elems.size(); - if (index<-size || index>=size) { - return nullptr; - } - return &elems[index>=0? index:index+size]; -} - std::ostream& operator<<(std::ostream& out, nas_vec& vec) { if (!vec.elems.size() || vec.printed) { out << (vec.elems.size()? "[..]":"[]"); @@ -40,7 +24,8 @@ std::ostream& operator<<(std::ostream& out, nas_vec& vec) { var nas_hash::get_value(const std::string& key) { if (elems.count(key)) { return elems.at(key); - } else if (!elems.count("parents")) { + } + if (!elems.count("parents")) { return var::none(); } @@ -63,7 +48,8 @@ var nas_hash::get_value(const std::string& key) { var* nas_hash::get_memory(const std::string& key) { if (elems.count(key)) { return &elems.at(key); - } else if (!elems.count("parents")) { + } + if (!elems.count("parents")) { return nullptr; } @@ -279,12 +265,6 @@ void nas_val::clear() { } } -f64 var::to_num() const { - return type != vm_type::vm_str - ? val.num - : util::str_to_num(str().c_str()); -} - std::string var::to_str() { if (type==vm_type::vm_str) { return str(); diff --git a/src/nasal_type.h b/src/nasal_type.h index 3c240d5..fb283ed 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -1,6 +1,7 @@ #pragma once #include "nasal.h" +#include "util/util.h" #include #include @@ -173,8 +174,13 @@ public: bool is_map() const { return type == vm_type::vm_map; } public: - // number and string can be translated to each other - f64 to_num() const; + // convert to number + f64 to_num() const { + return type != vm_type::vm_str + ? val.num + : util::str_to_num(str().c_str()); + } + // convert to string std::string to_str(); inline bool object_check(const std::string&) const; friend std::ostream& operator<<(std::ostream&, var&); @@ -187,8 +193,20 @@ struct nas_vec { bool printed = false; auto size() const { return elems.size(); } - var get_value(const i32); - var* get_memory(const i32); + var get_value(const i32 index) { + i32 size = elems.size(); + if (index < -size || index >= size) { + return var::none(); + } + return elems[index >= 0 ? index : index + size]; + } + var* get_memory(const i32 index) { + i32 size = elems.size(); + if (index < -size || index >= size) { + return nullptr; + } + return &elems[index >= 0 ? index : index + size]; + } friend std::ostream& operator<<(std::ostream&, nas_vec&); }; diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 62c1f87..312d031 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -97,6 +97,7 @@ protected: protected: /* vm calculation functions*/ inline bool boolify(const var&); + inline void set_frame(const nas_func&, var*); protected: /* vm operands */ @@ -342,6 +343,15 @@ inline bool vm::boolify(const var& val) { return false; } +inline void vm::set_frame(const nas_func& func, var* local) { + ctx.top[0] = ctx.upvalr; + (++ctx.top)[0] = var::addr(ctx.localr); + (++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret + ctx.pc = func.entry - 1; + ctx.localr = local; + ctx.upvalr = nil; +} + inline void vm::o_repl() { // reserved for repl mode stack top value output if (allow_repl_output) { @@ -935,12 +945,7 @@ inline void vm::o_callfv() { ? parameter_size + 1 : func.local_size - 1] = dynamic; - ctx.top[0] = ctx.upvalr; - (++ctx.top)[0] = var::addr(ctx.localr); - (++ctx.top)[0] = var::ret(ctx.pc); - ctx.pc = func.entry-1; - ctx.localr = local; - ctx.upvalr = nil; + set_frame(func, local); } inline void vm::o_callfh() { @@ -987,12 +992,7 @@ inline void vm::o_callfh() { return; } - ctx.top[0] = ctx.upvalr; - (++ctx.top)[0] = var::addr(ctx.localr); - (++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret - ctx.pc=func.entry-1; - ctx.localr = local; - ctx.upvalr = nil; + set_frame(func, local); } inline void vm::o_callb() { diff --git a/src/natives/dylib_lib.cpp b/src/natives/dylib_lib.cpp index d405974..61e1002 100644 --- a/src/natives/dylib_lib.cpp +++ b/src/natives/dylib_lib.cpp @@ -18,35 +18,64 @@ void dynamic_library_destructor(void* pointer) { #endif } +std::vector possible_dylib_path() { + const auto env_path = std::string(getenv("PATH")); + const auto sep = (util::is_windows()? ";":":"); + const auto path_front = util::is_windows()? "\\module\\":"/module/"; + + // do split string + std::vector env_path_vec = {"."}; + usize last = 0; + usize pos = env_path.find(sep, 0); + while(pos != std::string::npos) { + if (pos > last) { + env_path_vec.push_back(env_path.substr(last, pos - last)); + } + last = pos + 1; + pos = env_path.find(sep, last); + } + if (last != env_path.length()) { + env_path_vec.push_back(env_path.substr(last)); + } + + for (auto& p : env_path_vec) { + p += path_front; + } + + return env_path_vec; +} + std::string search_dynamic_library_path(const std::string& dlname) { const auto ext = (util::is_windows()? ".dll":".so"); const auto lib_path = (util::is_windows()? ".\\":"./") + dlname + ext; if (fs::exists(lib_path)) { return lib_path; } - const auto env_path = std::string(getenv("PATH")); - const auto sep = (util::is_windows()? ";":":"); - - // do split string - std::vector env_path_vec = {"."}; - usize last = 0; - usize pos = env_path.find(sep, 0); - while(pos!=std::string::npos) { - if (pos>last) { - env_path_vec.push_back(env_path.substr(last, pos-last)); + // macos may use .dylib as extension + if (util::is_macos()) { + const auto dylib_path = "./" + dlname + ".dylib"; + if (fs::exists(dylib_path)) { + return dylib_path; } - last = pos + 1; - pos = env_path.find(sep, last); - } - if (last!=env_path.length()) { - env_path_vec.push_back(env_path.substr(last)); } - const auto path_front = util::is_windows()? "\\module\\":"/module/"; - for(auto& p : env_path_vec) { - p += path_front + lib_path; - if (fs::exists(p)) { - return p; + // search library in PATH + const auto possible_path = possible_dylib_path(); + for(const auto& p : possible_path) { + const auto env_p = p + lib_path; + if (fs::exists(env_p)) { + return env_p; + } + } + + // macos may use .dylib as extension + if (util::is_macos()) { + const auto dylib_path = "./" + dlname + ".dylib"; + for(const auto& p : possible_path) { + const auto env_p = p + dylib_path; + if (fs::exists(env_p)) { + return env_p; + } } } return ""; @@ -61,7 +90,7 @@ var builtin_dlopen(context* ctx, gc* ngc) { const auto dlname = search_dynamic_library_path(dl.str()); if (dlname.empty()) { return nas_err("dylib::dlopen", - "cannot find dynamic lib <" + dl.str() + ">" + "cannot find dynamic library <" + dl.str() + ">" ); } diff --git a/src/natives/dylib_lib.h b/src/natives/dylib_lib.h index 67a9ef0..c4ae80f 100644 --- a/src/natives/dylib_lib.h +++ b/src/natives/dylib_lib.h @@ -13,11 +13,13 @@ #include #include +#include namespace nasal { void dynamic_library_destructor(void*); +std::vector possible_dylib_path(); std::string search_dynamic_library_path(const std::string&); var builtin_dlopen(context*, gc*); From dadc0afa35ce81402a4c8d8c7cf4bc59df20fdde Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Fri, 3 Jan 2025 01:07:46 +0800 Subject: [PATCH 07/12] :bug: fix build failure --- module/makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/module/makefile b/module/makefile index 981ab8c..2417329 100644 --- a/module/makefile +++ b/module/makefile @@ -24,45 +24,45 @@ winall: $(dynamic_libs_dll) libfib.so: fib.cpp $(used_header) $(used_object) @ echo "[Compiling] libfib.so" - @ $(CXX) $(CXXFLAGS) fib.cpp -o fib.o + @ $(CXX) $(CXXFLAGS) fib.cpp -o fib.o -I ../src @ $(CXX) -shared -o libfib.so fib.o $(used_object) @ rm fib.o libfib.dll: fib.cpp $(used_header) $(used_object) @ echo [Compiling] libfib.dll - @ $(CXX) -std=$(STD) -c -O3 fib.cpp -fPIC -o fib.o + @ $(CXX) -std=$(STD) -c -O3 fib.cpp -fPIC -o fib.o -I ../src @ $(CXX) -shared -o libfib.dll fib.o $(used_object) -static @ del fib.o libkey.so: keyboard.cpp $(used_header) $(used_object) @ echo "[Compiling] libkey.so" - @ $(CXX) $(CXXFLAGS) keyboard.cpp -o keyboard.o + @ $(CXX) $(CXXFLAGS) keyboard.cpp -o keyboard.o -I ../src @ $(CXX) -shared -o libkey.so keyboard.o $(used_object) @ rm keyboard.o libkey.dll: keyboard.cpp $(used_header) $(used_object) @ echo [Compiling] libkey.dll - @ $(CXX) -std=$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static + @ $(CXX) -std=$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static -I ../src @ $(CXX) -shared -o libkey.dll keyboard.o $(used_object) -static @ del keyboard.o libnasock.so: nasocket.cpp $(used_header) $(used_object) @ echo "[Compiling] libnasock.so" - @ $(CXX) $(CXXFLAGS) nasocket.cpp -o nasocket.o + @ $(CXX) $(CXXFLAGS) nasocket.cpp -o nasocket.o -I ../src @ $(CXX) -shared -o libnasock.so nasocket.o $(used_object) @ rm nasocket.o libnasock.dll: nasocket.cpp $(used_header) $(used_object) @ echo [Compiling] libnasock.dll - @ $(CXX) -std=$(STD) -c -O3 nasocket.cpp -fPIC -o nasocket.o -lwsock32 -static + @ $(CXX) -std=$(STD) -c -O3 nasocket.cpp -fPIC -I ../src -o nasocket.o -lwsock32 -static @ $(CXX) -shared -o libnasock.dll nasocket.o $(used_object) -lwsock32 -static @ del nasocket.o libmat.so: matrix.cpp $(used_header) $(used_object) @ echo "[Compiling] libmat.so" - @ $(CXX) $(CXXFLAGS) matrix.cpp -o matrix.o + @ $(CXX) $(CXXFLAGS) matrix.cpp -o matrix.o -I ../src @ $(CXX) -shared -o libmat.so matrix.o $(used_object) @ rm matrix.o libmat.dll: matrix.cpp $(used_header) $(used_object) @ echo [Compiling] libmat.dll - @ $(CXX) -std=$(STD) -c -O3 matrix.cpp -fPIC -o matrix.o -static + @ $(CXX) -std=$(STD) -c -O3 matrix.cpp -fPIC -I ../src -o matrix.o -static @ $(CXX) -shared -o libmat.dll matrix.o $(used_object) -static @ del matrix.o From c228dcc149f72c120a316d7f69ee703a30334895 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 11 Jan 2025 17:51:34 +0800 Subject: [PATCH 08/12] :memo: change makefile --- module/makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/module/makefile b/module/makefile index 2417329..6445e8a 100644 --- a/module/makefile +++ b/module/makefile @@ -12,9 +12,9 @@ ifndef OS OS = $(shell uname) endif ifeq ($(OS), Darwin) - CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 + CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I ../src else - CXXFLAGS = -std=$(STD) -c -O3 -fPIC + CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I ../src endif all: $(dynamic_libs_so) @@ -24,7 +24,7 @@ winall: $(dynamic_libs_dll) libfib.so: fib.cpp $(used_header) $(used_object) @ echo "[Compiling] libfib.so" - @ $(CXX) $(CXXFLAGS) fib.cpp -o fib.o -I ../src + @ $(CXX) $(CXXFLAGS) fib.cpp -o fib.o @ $(CXX) -shared -o libfib.so fib.o $(used_object) @ rm fib.o libfib.dll: fib.cpp $(used_header) $(used_object) @@ -35,7 +35,7 @@ libfib.dll: fib.cpp $(used_header) $(used_object) libkey.so: keyboard.cpp $(used_header) $(used_object) @ echo "[Compiling] libkey.so" - @ $(CXX) $(CXXFLAGS) keyboard.cpp -o keyboard.o -I ../src + @ $(CXX) $(CXXFLAGS) keyboard.cpp -o keyboard.o @ $(CXX) -shared -o libkey.so keyboard.o $(used_object) @ rm keyboard.o libkey.dll: keyboard.cpp $(used_header) $(used_object) @@ -46,7 +46,7 @@ libkey.dll: keyboard.cpp $(used_header) $(used_object) libnasock.so: nasocket.cpp $(used_header) $(used_object) @ echo "[Compiling] libnasock.so" - @ $(CXX) $(CXXFLAGS) nasocket.cpp -o nasocket.o -I ../src + @ $(CXX) $(CXXFLAGS) nasocket.cpp -o nasocket.o @ $(CXX) -shared -o libnasock.so nasocket.o $(used_object) @ rm nasocket.o libnasock.dll: nasocket.cpp $(used_header) $(used_object) @@ -57,7 +57,7 @@ libnasock.dll: nasocket.cpp $(used_header) $(used_object) libmat.so: matrix.cpp $(used_header) $(used_object) @ echo "[Compiling] libmat.so" - @ $(CXX) $(CXXFLAGS) matrix.cpp -o matrix.o -I ../src + @ $(CXX) $(CXXFLAGS) matrix.cpp -o matrix.o @ $(CXX) -shared -o libmat.so matrix.o $(used_object) @ rm matrix.o libmat.dll: matrix.cpp $(used_header) $(used_object) From 277ddb9c0f44c24951b3e5f57002977e8c6caef6 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 11 Jan 2025 21:06:57 +0800 Subject: [PATCH 09/12] :sparkles: add demo format executable --- .gitignore | 2 + CMakeLists.txt | 13 ++ src/ast_dumper.h | 2 +- src/ast_format.cpp | 412 +++++++++++++++++++++++++++++++++++++++++++++ src/ast_format.h | 144 ++++++++++++++++ src/cli/cli.cpp | 77 +++++++++ src/cli/cli.h | 5 + src/format.cpp | 56 ++++++ src/main.cpp | 55 +----- 9 files changed, 714 insertions(+), 52 deletions(-) create mode 100644 src/ast_format.cpp create mode 100644 src/ast_format.h create mode 100644 src/format.cpp diff --git a/.gitignore b/.gitignore index 76f7285..b3a00de 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,9 @@ cmake-windows-* *.out *.app nasal +nasal-format nasal.exe +nasal-format.exe # Visual Studio specific *.sln diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb6a3f..a04118e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ set(NASAL_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/util/fs.cpp ${CMAKE_SOURCE_DIR}/src/util/util.cpp ${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp + ${CMAKE_SOURCE_DIR}/src/ast_format.cpp ${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp ${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp ${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp @@ -62,12 +63,18 @@ target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src) add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp) target_link_libraries(nasal nasal-object) +# build nasal-format +add_executable(nasal-format ${CMAKE_SOURCE_DIR}/src/format.cpp) +target_link_libraries(nasal-format nasal-object) + # link ldl and lpthread if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") target_link_libraries(nasal dl) target_link_libraries(nasal pthread) + target_link_libraries(nasal-format pthread) endif() target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(nasal-format PRIVATE ${CMAKE_SOURCE_DIR}/src) # copy nasal from build dir to the outside dir if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") @@ -77,6 +84,12 @@ if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") ${CMAKE_SOURCE_DIR}/build/nasal ${CMAKE_SOURCE_DIR}/nasal ) + add_custom_command( + TARGET nasal-format POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/build/nasal-format + ${CMAKE_SOURCE_DIR}/nasal-format + ) endif() # build module diff --git a/src/ast_dumper.h b/src/ast_dumper.h index 1586d0b..e8c5565 100644 --- a/src/ast_dumper.h +++ b/src/ast_dumper.h @@ -38,7 +38,7 @@ private: if (indent.size() && indent.back()=="│ ") { indent.back() = "├──"; } - for(const auto& i : indent) { + for (const auto& i : indent) { std::cout << i; } } diff --git a/src/ast_format.cpp b/src/ast_format.cpp new file mode 100644 index 0000000..f50b822 --- /dev/null +++ b/src/ast_format.cpp @@ -0,0 +1,412 @@ +#include "ast_format.h" +#include "util/util.h" + +#include + +namespace nasal { + +bool ast_format::visit_use_stmt(use_stmt* node) { + dump_formating_node_info(node, "use statement"); + out << "use "; + for(auto i : node->get_path()) { + i->accept(this); + if (i != node->get_path().back()) { + out << "."; + } + } + return true; +} + +bool ast_format::visit_null_expr(null_expr* node) { + dump_formating_node_info(node, "null expression"); + out << "null"; + return true; +} + +bool ast_format::visit_nil_expr(nil_expr* node) { + dump_formating_node_info(node, "nil expression"); + out << "nil"; + return true; +} + +bool ast_format::visit_number_literal(number_literal* node) { + dump_formating_node_info(node, "number expression"); + out << node->get_number(); + return true; +} + +bool ast_format::visit_string_literal(string_literal* node) { + dump_formating_node_info(node, "string expression"); + out << "\"" << util::rawstr(node->get_content()) << "\""; + return true; +} + +bool ast_format::visit_identifier(identifier* node) { + dump_formating_node_info(node, "identifier"); + out << node->get_name(); + return true; +} + +bool ast_format::visit_bool_literal(bool_literal* node) { + dump_formating_node_info(node, "bool expression"); + out << (node->get_flag()? "true" : "false"); + return true; +} + +bool ast_format::visit_vector_expr(vector_expr* node) { + dump_formating_node_info(node, "vector expression"); + out << "["; + for(auto i : node->get_elements()) { + i->accept(this); + if (i != node->get_elements().back()) { + out << ", "; + } + } + out << "]"; + return true; +} + +bool ast_format::visit_hash_expr(hash_expr* node) { + dump_formating_node_info(node, "hash expression"); + out << "{"; + for(auto i : node->get_members()) { + i->accept(this); + if (i != node->get_members().back()) { + out << ", "; + } + } + out << "}"; + return true; +} + +bool ast_format::visit_hash_pair(hash_pair* node) { + dump_formating_node_info(node, "hash pair"); + out << node->get_name(); + if (node->get_value()) { + out << " : "; + node->get_value()->accept(this); + } + return true; +} + +bool ast_format::visit_function(function* node) { + dump_formating_node_info(node, "function"); + out << "func("; + for(auto i : node->get_parameter_list()) { + i->accept(this); + if (i != node->get_parameter_list().back()) { + out << ", "; + } + } + out << ") "; + node->get_code_block()->accept(this); + return true; +} + +bool ast_format::visit_code_block(code_block* node) { + dump_formating_node_info(node, "code block"); + out << "{\n"; + push_indent(); + for(auto i : node->get_expressions()) { + dump_indent(); + i->accept(this); + if (need_dump_semi(i)) { + out << ";\n"; + } else { + out << "\n"; + } + } + pop_indent(); + dump_indent(); + out << "}"; + return true; +} + +bool ast_format::visit_parameter(parameter* node) { + dump_formating_node_info(node, "parameter"); + out << node->get_parameter_name(); + switch (node->get_parameter_type()) { + case parameter::kind::normal_parameter: break; + case parameter::kind::dynamic_parameter: out << "..."; break; + case parameter::kind::default_parameter: out << " = "; break; + } + if (node->get_default_value()) { + node->get_default_value()->accept(this); + } + return true; +} + +bool ast_format::visit_ternary_operator(ternary_operator* node) { + dump_formating_node_info(node, "ternary operator"); + node->get_condition()->accept(this); + out << " ? "; + node->get_left()->accept(this); + out << " : "; + node->get_right()->accept(this); + return true; +} + +bool ast_format::visit_binary_operator(binary_operator* node) { + dump_formating_node_info(node, "binary operator"); + out << "("; + node->get_left()->accept(this); + switch(node->get_operator_type()) { + case binary_operator::kind::add: out << " + "; break; + case binary_operator::kind::sub: out << " - "; break; + case binary_operator::kind::mult: out << " * "; break; + case binary_operator::kind::div: out << " / "; break; + case binary_operator::kind::concat: out << " ~ "; break; + case binary_operator::kind::bitwise_and: out << " & "; break; + case binary_operator::kind::bitwise_or: out << " | "; break; + case binary_operator::kind::bitwise_xor: out << " ^ "; break; + case binary_operator::kind::cmpeq: out << " == "; break; + case binary_operator::kind::cmpneq: out << " != "; break; + case binary_operator::kind::grt: out << " > "; break; + case binary_operator::kind::geq: out << " >= "; break; + case binary_operator::kind::less: out << " < "; break; + case binary_operator::kind::leq: out << " <= "; break; + case binary_operator::kind::condition_and: out << " and "; break; + case binary_operator::kind::condition_or: out << " or "; break; + case binary_operator::kind::null_chain: out << " ?? "; break; + } + node->get_right()->accept(this); + out << ")"; + return true; +} + +bool ast_format::visit_unary_operator(unary_operator* node) { + dump_formating_node_info(node, "unary operator"); + switch(node->get_operator_type()) { + case unary_operator::kind::negative: out << "-"; break; + case unary_operator::kind::logical_not: out << "!"; break; + case unary_operator::kind::bitwise_not: out << "~"; break; + } + node->get_value()->accept(this); + return true; +} + +bool ast_format::visit_call_expr(call_expr* node) { + dump_formating_node_info(node, "call expression"); + node->get_first()->accept(this); + for(auto i : node->get_calls()) { + i->accept(this); + } + return true; +} + +bool ast_format::visit_call_hash(call_hash* node) { + dump_formating_node_info(node, "call hash"); + out << "." << node->get_field(); + return true; +} + +bool ast_format::visit_null_access(null_access* node) { + dump_formating_node_info(node, "null access operator(?.)"); + out << "?." << node->get_field(); + return true; +} + +bool ast_format::visit_call_vector(call_vector* node) { + dump_formating_node_info(node, "call vector"); + out << "["; + for(auto i : node->get_slices()) { + i->accept(this); + if (i != node->get_slices().back()) { + out << ", "; + } + } + out << "]"; + return true; +} + +bool ast_format::visit_call_function(call_function* node) { + dump_formating_node_info(node, "call function"); + out << "("; + for(auto i : node->get_argument()) { + i->accept(this); + if (i != node->get_argument().back()) { + out << ", "; + } + } + out << ")"; + return true; +} + +bool ast_format::visit_slice_vector(slice_vector* node) { + dump_formating_node_info(node, "slice vector"); + node->get_begin()->accept(this); + if (node->get_end()) { + out << " : "; + node->get_end()->accept(this); + } + return true; +} + +bool ast_format::visit_definition_expr(definition_expr* node) { + dump_formating_node_info(node, "definition"); + out << "var "; + if (node->get_variable_name()) { + node->get_variable_name()->accept(this); + } else { + node->get_variables()->accept(this); + } + out << " = "; + if (node->get_tuple()) { + node->get_tuple()->accept(this); + } else { + node->get_value()->accept(this); + } + return true; +} + +bool ast_format::visit_assignment_expr(assignment_expr* node) { + dump_formating_node_info(node, "assignment"); + node->get_left()->accept(this); + switch(node->get_assignment_type()) { + case assignment_expr::kind::add_equal: out << " += "; break; + case assignment_expr::kind::sub_equal: out << " -= "; break; + case assignment_expr::kind::mult_equal: out << " *= "; break; + case assignment_expr::kind::div_equal: out << " /= "; break; + case assignment_expr::kind::concat_equal: out << " ~= "; break; + case assignment_expr::kind::equal: out << " = "; break; + case assignment_expr::kind::bitwise_and_equal: out << " &= "; break; + case assignment_expr::kind::bitwise_or_equal: out << " |= "; break; + case assignment_expr::kind::bitwise_xor_equal: out << " ^= "; break; + } + node->get_right()->accept(this); + return true; +} + +bool ast_format::visit_multi_identifier(multi_identifier* node) { + dump_formating_node_info(node, "multi identifier"); + out << "("; + for(auto i : node->get_variables()) { + i->accept(this); + if (i != node->get_variables().back()) { + out << ", "; + } + } + out << ")"; + return true; +} + +bool ast_format::visit_tuple_expr(tuple_expr* node) { + dump_formating_node_info(node, "tuple expression"); + out << "("; + for(auto i : node->get_elements()) { + i->accept(this); + if (i != node->get_elements().back()) { + out << ", "; + } + } + out << ")"; + return true; +} + +bool ast_format::visit_multi_assign(multi_assign* node) { + dump_formating_node_info(node, "multi assign"); + node->get_tuple()->accept(this); + out << " = "; + node->get_value()->accept(this); + return true; +} + +bool ast_format::visit_while_expr(while_expr* node) { + dump_formating_node_info(node, "while statement"); + out << "while ("; + node->get_condition()->accept(this); + out << ") "; + node->get_code_block()->accept(this); + return true; +} + +bool ast_format::visit_for_expr(for_expr* node) { + dump_formating_node_info(node, "for statement"); + out << "for ("; + node->get_initial()->accept(this); + out << "; "; + node->get_condition()->accept(this); + out << "; "; + node->get_step()->accept(this); + out << ") "; + node->get_code_block()->accept(this); + return true; +} + +bool ast_format::visit_iter_expr(iter_expr* node) { + dump_formating_node_info(node, "iteration expression"); + if (node->is_definition()) { + out << "var "; + } + if (node->get_name()) { + node->get_name()->accept(this); + } else { + node->get_call()->accept(this); + } + return true; +} + +bool ast_format::visit_forei_expr(forei_expr* node) { + dump_formating_node_info(node, "forindex/foreach statement"); + if (node->get_loop_type()==forei_expr::kind::foreach) { + out << "foreach "; + } else { + out << "forindex "; + } + out << "("; + node->get_iterator()->accept(this); + out << "; "; + node->get_value()->accept(this); + out << ") "; + node->get_code_block()->accept(this); + return true; +} + +bool ast_format::visit_condition_expr(condition_expr* node) { + dump_formating_node_info(node, "condition statement"); + out << "if "; + node->get_if_statement()->accept(this); + for (auto i : node->get_elsif_stataments()) { + out << " elsif "; + i->accept(this); + } + if (node->get_else_statement()) { + out << " else "; + node->get_else_statement()->accept(this); + } + return true; +} + +bool ast_format::visit_if_expr(if_expr* node) { + dump_formating_node_info(node, "if statement"); + if (node->get_condition()) { + out << "("; + node->get_condition()->accept(this); + out << ") "; + } + node->get_code_block()->accept(this); + return true; +} + +bool ast_format::visit_continue_expr(continue_expr* node) { + dump_formating_node_info(node, "continue statement"); + out << "continue"; + return true; +} + +bool ast_format::visit_break_expr(break_expr* node) { + dump_formating_node_info(node, "break statement"); + out << "break"; + return true; +} + +bool ast_format::visit_return_expr(return_expr* node) { + dump_formating_node_info(node, "return statement"); + out << "return "; + if (node->get_value()) { + node->get_value()->accept(this); + } + return true; +} + +} diff --git a/src/ast_format.h b/src/ast_format.h new file mode 100644 index 0000000..8f3b23c --- /dev/null +++ b/src/ast_format.h @@ -0,0 +1,144 @@ +#pragma once + +#include "ast_visitor.h" + +#include +#include +#include +#include +#include +#include + +namespace nasal { + +class ast_format: public ast_visitor { +private: + std::ofstream out; + std::vector indent; + +private: + void push_indent() { + indent.push_back(" "); + } + void pop_indent() { + if (indent.size()) { + indent.pop_back(); + } + } + void dump_indent() { + for (const auto& i : indent) { + out << i; + } + } + void dump_formating_node_info(expr* n, const char* name) { + std::cout << " formating " << name << " @ 0x"; + std::cout << std::hex << n << std::dec << "\n"; + } + bool need_dump_semi(expr* n) { + switch (n->get_type()) { + case expr_type::ast_use: + case expr_type::ast_null: + case expr_type::ast_nil: + case expr_type::ast_num: + case expr_type::ast_str: + case expr_type::ast_bool: + case expr_type::ast_vec: + case expr_type::ast_hash: + case expr_type::ast_call: return true; + case expr_type::ast_def: { + auto dn = reinterpret_cast(n); + if (dn->get_value() && + dn->get_value()->get_type() == expr_type::ast_func) { + return false; + } + return true; + } + case expr_type::ast_assign: { + auto dn = reinterpret_cast(n); + if (dn->get_right() && + dn->get_right()->get_type() == expr_type::ast_func) { + return false; + } + return true; + } + case expr_type::ast_ret: { + auto dn = reinterpret_cast(n); + if (dn->get_value() && + dn->get_value()->get_type() == expr_type::ast_func) { + return false; + } + return true; + } + default: break; + } + + return false; + } + +public: + bool visit_use_stmt(use_stmt*) override; + bool visit_null_expr(null_expr*) override; + bool visit_nil_expr(nil_expr*) override; + bool visit_number_literal(number_literal*) override; + bool visit_string_literal(string_literal*) override; + bool visit_identifier(identifier*) override; + bool visit_bool_literal(bool_literal*) override; + bool visit_vector_expr(vector_expr*) override; + bool visit_hash_expr(hash_expr*) override; + bool visit_hash_pair(hash_pair*) override; + bool visit_function(function*) override; + bool visit_code_block(code_block*) override; + bool visit_parameter(parameter*) override; + bool visit_ternary_operator(ternary_operator*) override; + bool visit_binary_operator(binary_operator*) override; + bool visit_unary_operator(unary_operator*) override; + bool visit_call_expr(call_expr*) override; + bool visit_call_hash(call_hash*) override; + bool visit_null_access(null_access*) override; + bool visit_call_vector(call_vector*) override; + bool visit_call_function(call_function*) override; + bool visit_slice_vector(slice_vector*) override; + bool visit_definition_expr(definition_expr*) override; + bool visit_assignment_expr(assignment_expr*) override; + bool visit_multi_identifier(multi_identifier*) override; + bool visit_tuple_expr(tuple_expr*) override; + bool visit_multi_assign(multi_assign*) override; + bool visit_while_expr(while_expr*) override; + bool visit_for_expr(for_expr*) override; + bool visit_iter_expr(iter_expr*) override; + bool visit_forei_expr(forei_expr*) override; + bool visit_condition_expr(condition_expr*) override; + bool visit_if_expr(if_expr*) override; + bool visit_continue_expr(continue_expr*) override; + bool visit_break_expr(break_expr*) override; + bool visit_return_expr(return_expr*) override; + +public: + ast_format(const std::string output_file): out(output_file) { + if (out.fail()) { + throw std::runtime_error("can't open file: " + output_file); + } + } + + void do_format(code_block* root) { + std::cout << "nasal-format is not stable right now, "; + std::cout << "take care of source code!\n"; + dump_formating_node_info(root, "program root"); + bool is_use_statement = true; + for (auto i : root->get_expressions()) { + if (is_use_statement && i->get_type() != expr_type::ast_use) { + is_use_statement = false; + out << "\n"; + } + + i->accept(this); + if (need_dump_semi(i)) { + out << ";\n"; + } else { + out << "\n"; + } + } + } +}; + +} diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 8605fa1..9961467 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1,6 +1,12 @@ +#include "nasal.h" #include "cli/cli.h" +#include "util/util.h" +#include "nasal_parse.h" #include +#include +#include +#include namespace nasal::cli { @@ -59,4 +65,75 @@ std::ostream& help(std::ostream& out) { return out; } +std::ostream& nasal_format_help(std::ostream& out) { + out + << "\n" + << " ,--#-,\n" + << "<3 / \\____\\ <3\n" + << " |_|__A_|\n" + << "\nnasal-format