Skip to content

Commit

Permalink
Deprecated elsif, new "chaining" syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
Edd12321 committed Jul 18, 2023
1 parent fcc214e commit 2e5d788
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 52 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Zrc is just ~600KB in size because its implementation is to the point and simple
- [X] Return value (`[...]`)
- [X] Built-in commands (like `expr`, `jobs`, etc. but there are too many to list. View `dispatch.hpp`)
- [X] Conditional logic/flow control with full C arithmetic operator set
- [X] If/elsif/else
- [X] If/else
- [X] Do
- [X] While
- [X] Foreach
Expand Down
2 changes: 1 addition & 1 deletion doc/man1/expr.1
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ which writes to stdout, so square brackets should be used to access it.
.RB * , / , // , % ;
.SS Precedence level 13: implicit
.SS Functions
.RB log10 , log2 , log , sqrt , sin , cos , ctg , tg , floor , ceil , abs;
.RB log10 , log2 , log , sqrt , sin , cos , ctg , tg , floor , ceil , abs , round;
.SS Other words
.RB nan , false , true ;
.SS Unary operators
Expand Down
20 changes: 8 additions & 12 deletions doc/man1/fn.1
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,20 @@ Alternatively, you can trap a signal by defining a function with the name of tha
fn is_prime {
if {$argv(1) < 2} {
return 0
} elsif {$argv(1) == 2) {
} else if {$argv(1) == 2} {
return 1
} elsif {$argv(1) % 2 == 0} {
} else if {$argv(1) % 2 == 0} {
return 0
} else {
let {i ok} {
set ok = 1
for {set i = 3} {$i <= $argv(1)/2} {inc i} {
if {$argv(1) % $i == 0} {
set ok = 0
set i = $argv(1)
}
} else let i {
for {set i = 3} {$i <= $argv(1)/2} {inc i} {
if {$argv(1) % $i == 0} {
return 0
}
return $ok
}
return 1
}
}
##################
# Trap SIGWINCH. #
##################
Expand Down
19 changes: 9 additions & 10 deletions doc/man1/if.1
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
.SH NAME
if \- Execute script body if a condition is met
.SH SYNOPSIS
.BI "if " "<expr> <block>" " [elsif " "<expr> <block>..." "|else " <block> ]
.BI "if " "<expr> <block>" " [else " "< <block>" | "<w1> <w2>...<wn> >" ]
.SH DESCRIPTION
The
.I if
command evaluates its first argument as an 'expr' expression and executes the second argument as a script if said expression is true. If it is not true, it checks the next argument. If it is
.BR elsif ,
it evaluates the argument next to it as an expression and executes another function body, otherwise if it is
.BR else
ii evaluates the argument next to it regardless of an expression. This can repeat for as many times as necessary.
.BR else ,
it either evaluates one single argument as a script, or treats its remaining arguments as words for a new command to be exec'd via Bernstein chaining (NOT evaled!).
.SH EXAMPLE
.EX
set i = 0
if {i == -2} {
if {$i == -2} {
echo this shouldn\\'t happen
} elsif {i == -1} {
} else if {$i == -1} {
echo elsif test
} elsif {i > 0} {
} else if {$i > 0} {
echo elsif test \\# 2
} else {
echo 0 equals 0 true
} else while {$i < 10} {
echo '$i < 10'
set i += 1
}
.EE
2 changes: 1 addition & 1 deletion doc/man1/zrc.1
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ Looping construct #3.
.br
List all commands.
.HP
.BI "if " "<expr> <block>" " [elsif " "<expr> <block>..." "|else " <block> ]
.BI "if " "<expr> <block>" " [else " "< <block>" | "<w1> <w2>...<wn> >" ]
.br
Conditional statement #1.
.HP
Expand Down
17 changes: 17 additions & 0 deletions examples/bernstein_chaining.zrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!../bin/zrc
set i = 0
read -p "What to do? (0, 1, 2 or something else) " x

if {$x == 0} {
ls | wc -mlw
cd ~/
} else {
if {$x == 1} {
echo 'You entered 1!'
} else if {$x == 2} {
echo 'You entered 2!'
} else while {$i < 10} {
echo $i
inc i
}
}
Empty file modified examples/forkbomb.zrc
100755 → 100644
Empty file.
6 changes: 1 addition & 5 deletions examples/quicksort.zrc
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ fn quicksort {
}
set $vn = '$$vn $x'
}
return [concat \
[quicksort $less] \
$equal \
[quicksort $greater]
];
return [concat [quicksort $less] $equal [quicksort $greater]]
}
}

Expand Down
8 changes: 4 additions & 4 deletions examples/server.zrc
Original file line number Diff line number Diff line change
Expand Up @@ -72,24 +72,24 @@ fn remo {
ssh-agent -k &

#2:
} elsif {[string cmp $argv(1) "dialog"] == 0} {
} else if {[string cmp $argv(1) "dialog"] == 0} {
log "\[Remote-controlled dialog window]";
zenity --info \
--title="Dialog Box"\
--text="test"

#3:
} elsif {[string cmp $argv(1) "killsv"] == 0} {
} else if {[string cmp $argv(1) "killsv"] == 0} {
log "\[Exiting server]"
exit

#4:
} elsif {[string cmp $argv(1) "shutdn"] == 0} {
} else if {[string cmp $argv(1) "shutdn"] == 0} {
log "\[Shutting down]"
poweroff

#5:
} elsif {[string cmp $argv(1) "clrscr"] == 0} {
} else if {[string cmp $argv(1) "clrscr"] == 0} {
clear

#6:
Expand Down
2 changes: 1 addition & 1 deletion examples/sieve.zrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn sieve {
for {set p = 2} {$p <= $n} {inc p} {
if {$prime($p)} {
set ANSI = {\e[0;31m}
} elsif {$p == 42} {
} else if {$p == 42} {
set ANSI = {\e[0;32m}
} else {
set ANSI = {\e[0m}
Expand Down
26 changes: 26 additions & 0 deletions examples/speedtest.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

Bash will always be faster:
0.08user 0.08system 0:00.16elapsed 98%CPU (0avgtext+0avgdata 6788maxresident)k
0inputs+0outputs (0major+1106minor)pagefaults 0swaps

Fish is also fast, but uses more memory:
0.12user 0.07system 0:00.20elapsed 98%CPU (0avgtext+0avgdata 17200maxresident)k
0inputs+0outputs (0major+2663minor)pagefaults 0swaps

Csh will use more CPU power:
0.86user 1.10system 0:01.96elapsed 100%CPU (0avgtext+0avgdata 4036maxresident)k
0inputs+0outputs (3major+333953minor)pagefaults 0swaps

Zrc will also have lower memory consumption:
6.70user 22.51system 0:29.60elapsed 98%CPU (0avgtext+0avgdata 4508maxresident)k
0inputs+0outputs (9major+1381354minor)pagefaults 0swaps

Rc is comparable to Zrc in terms of performance:
8.60user 18.88system 0:27.75elapsed 99%CPU (0avgtext+0avgdata 2980maxresident)k
0inputs+0outputs (0major+3829864minor)pagefaults 0swaps

Powershell performs the worst:
29.91user 46.83system 1:10.31elapsed 109%CPU (0avgtext+0avgdata 124964maxresident)k
0inputs+296outputs (0major+745159minor)pagefaults 0swaps

CONCLUSION: Zrc doesn't totally suck ;) It's just very lightweight
64 changes: 64 additions & 0 deletions examples/speedtest.zrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/lib/zrc/bin/zrc
set env(tf) = `{mktemp}
set outfile = "speedtest.out"

rm -f $outfile && unbuffer -p zrc -c {
fn main {
echo "\nBash will always be faster:"
time bash -c {
for i in {1..10000}; do
# Print out to the file
printf '%d ' $i >> $tf
done
rm $tf
}

echo "\nFish is also fast, but uses more memory:"
time fish -c {
for i in (seq 0 10000)
printf '%d ' $i >> $tf
end
rm $tf
}

echo "\nCsh will use more CPU power:"
time csh <<< {
@ i = 0
while ($i <= 10000)
# Just a comment... test
printf '%d ' $i >> $tf
@ i += 5
end
rm $tf
}

echo "\nZrc will also have lower memory consumption:"
time zrc -c {
for {set i = 0} {$i <= 10000} {inc i} {
# This is a comment
printf '%d ' $i >> $env(tf)
}
rm $env(tf)
}

echo "\nRc is comparable to Zrc in terms of performance:"
time rc -c {
for (i in `{seq 0 10000}) {
# Rc has an AST, so comments don't affect performance
printf '%d ' $i >> $tf
}
rm $tf
}

echo "\nPowershell performs the worst:"
time >(1=) pwsh -c {
for ($i = 0; $i -lt 10000; ++$i) {
# Comment test
printf '%d ' $i >> $env:tf
}
rm $env:tf
}

echo "\nCONCLUSION: Zrc doesn't totally suck ;) It's just very lightweight"
}; main >(2=1)
} | tee $outfile
24 changes: 9 additions & 15 deletions src/dispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,19 @@ Command(expr) {

/** Executes a block if an expression evaluates non-zero **/
Command(if) {
constexpr char se[] = "<expr> <block> [else < <arg1> <arg2>... >|<block>]";
if (argc < 3)
syntax_error("<expr> <block> [elsif <expr> <block>...|else <block>]");
syntax_error(se);

if (OK(argv[1])) {
eval(argv[2]);
} else for (int i = 3; i < argc; i += 2) {
if (!strcmp(argv[i], "else")) {
if (i == argc-2)
eval(argv[i+1]);
else
syntax_error("else");
break;
}
if (!strcmp(argv[i], "elsif")) {
if (i <= argc-2 && OK(argv[++i])) {
eval(argv[i+1]);
break;
}
}
} else if (argc > 3 && !strcmp(argv[3], "else")) {
if (argc == 4)
syntax_error(se);
if (argc == 5)
eval(argv[4]);
else
exec(argc-4, argv+4);
}
NoReturn;
}
Expand Down
4 changes: 3 additions & 1 deletion src/exec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ exec(int argc, char *argv[])
for (auto const& it : baks)
dup2(it.first, it.second);
baks.clear();
for (i = 0; i < argc; ++i)
for (i = 0; i < argc; ++i) {
free(argv[i]);
argv[i] = NULL;
}
make_new_jobs = false;

// set fg group ID
Expand Down
2 changes: 1 addition & 1 deletion stdlib/list.zrc
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn lappend {
echo >(1=2) 'Expected 2 args!'
return {}
} else {
return [list {*}$argv(1) $argv(2)]
return [list {*}[subst $argv(1)] $argv(2)]
}
}

Expand Down

0 comments on commit 2e5d788

Please sign in to comment.