tdenniston / bish Goto Github PK
View Code? Open in Web Editor NEWBish is a language that compiles to Bash. It's designed to give shell scripting a more comfortable and modern feel.
License: MIT License
Bish is a language that compiles to Bash. It's designed to give shell scripting a more comfortable and modern feel.
License: MIT License
I am not sure if I am having the C++ Stdlib – how could I verify it? And how would I install it if necessary? I am using MacPorts.
Anyway, here is the compiler output:
⚡ make
g++ -g -O0 -c src/CallGraph.cpp -o obj/CallGraph.o -MMD -MF obj/CallGraph.d -MT obj/CallGraph.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/Compile.cpp -o obj/Compile.o -MMD -MF obj/Compile.d -MT obj/Compile.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/FindCalls.cpp -o obj/FindCalls.o -MMD -MF obj/FindCalls.d -MT obj/FindCalls.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/IR.cpp -o obj/IR.o -MMD -MF obj/IR.d -MT obj/IR.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/IRVisitor.cpp -o obj/IRVisitor.o -MMD -MF obj/IRVisitor.d -MT obj/IRVisitor.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/IRAncestorsPass.cpp -o obj/IRAncestorsPass.o -MMD -MF obj/IRAncestorsPass.d -MT obj/IRAncestorsPass.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
g++ -g -O0 -c src/CodeGen_Bash.cpp -o obj/CodeGen_Bash.o -MMD -MF obj/CodeGen_Bash.d -MT obj/CodeGen_Bash.o -DSTDLIB_PATH="\"/Users/tobi/.bish/src/StdLib.bish\""
couldn't understand kern.osversion `14.1.0'
src/CodeGen_Bash.cpp: In instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’:
src/CodeGen_Bash.cpp:41: instantiated from here
src/CodeGen_Bash.cpp:41: error: explicit instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ but no definition available
src/CodeGen_Bash.cpp: In instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’:
src/CodeGen_Bash.cpp:41: instantiated from here
src/CodeGen_Bash.cpp:41: error: explicit instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ but no definition available
src/CodeGen_Bash.cpp: In instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’:
src/CodeGen_Bash.cpp:41: instantiated from here
src/CodeGen_Bash.cpp:41: error: explicit instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ but no definition available
src/CodeGen_Bash.cpp: In instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’:
src/CodeGen_Bash.cpp:41: instantiated from here
src/CodeGen_Bash.cpp:41: error: explicit instantiation of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ but no definition available
make: *** [obj/CodeGen_Bash.o] Error 1
Each time not to cause this:
start = 100;
end = 150;
for (i in start .. end) {
if (i == 120) {
@(continue); # or @(break)
}
println(i);
}
Thus it is necessary to expand the built-in operators to be available more simple expressions.
Test case:
def f(x) {
println("x is: $x");
}
f("hello");
The argument $x does not get renamed to $1 during code generation:
function bish_f () {
bish_println "x is: $x";
}
Bish-script:
def double(val) {
return val * val;
}
for (i in 2 .. 4) {
d = i * i;
for (j in i .. d) {
print(double(j/i+j*i));
}
}
Bash-script:
#!/bin/bash
# ...
function bish_double () {
echo $(($1 * $1)); exit;
}
function bish_main () {
for i in $(seq 2 4); do
d=$(($i * $i));
for j in $(seq "$i" "$d"); do
bish_print "$(bish_double $(($(($j / $i)) + $(($j * $i)))))";
done;
}
done;
}
function bish_print () {
echo $1;
}
bish_main;
For example, the following code will not be translated:
var = "335f";
@($var =~ ^-?[0-9]+$);
Will be displayed parse error:
Parsing error: Expected variable to be a symbol near character ')', line 5
How best to do these teams? Maybe they wrap in quotes `?
Hi @tdenniston ,
I think it's important for script to support parse options from shell script command line .But it seems that there is no good way to do this in bish.
so I hope you can add something to support this.
Thank you.
shulei
If you have the bish script test.bish
:
assert(false);
And run it with:
bish -r test.bish
The exit code is 0 when it should be 1.
I would like to ask how it will be implemented?
You can make a semblance of annotations:
@root
cd('/home');
Or like this:
cd('/home') as root;
This is a relevant question, I think, for many users.
Here's a minimal test case that causes the compiler to hang:
@(
I want to use bish to partly rewrite https://github.com/AOSC-Dev/autobuild3 (The build tool of my Linux distro)
However, autobuild3 is modular and has many written bash routines.
How can I use them in bish?
PS: I don't like the generating style of bish -- It's not modular at all.
This looks very interesting to me; I share the author's frustration w/ bash
.
That being said, the syntax looks very much like C. I'm just wondering if there's a document on how to use this.
If not, w/ a little help from the author, I'd be glad to throw something together as a GitHub wiki page just to get people started.
Thanks for doing this!
Hi, @tdenniston
I have created just such a library: https://gist.github.com/eg0r/4da3b0d75cabcbe29e1f
PR did not do, as it is necessary to formalize the library. I propose to move it to a separate folder and there are going to bish-files to be imported one, for example, stdlib.bish
.
Yeah, well, I ask to comment on my code, it can be somehow need to improve?
Topic is relevant. You can do something like this, but it is better to determine the built-in function "eval". And then read the file and run it through this feature.
def import(f) {
@(./bish -r $f);
}
Bish should support simple array types.
Sounds good to me
Am I doing something wrong?
$ make
g++ -c src/CallGraph.cpp -o obj/CallGraph.o -MMD -MF obj/CallGraph.d -MT obj/CallGraph.o
g++ -c src/IR.cpp -o obj/IR.o -MMD -MF obj/IR.d -MT obj/IR.o
g++ -c src/IRVisitor.cpp -o obj/IRVisitor.o -MMD -MF obj/IRVisitor.d -MT obj/IRVisitor.o
g++ -c src/IRAncestorsPass.cpp -o obj/IRAncestorsPass.o -MMD -MF obj/IRAncestorsPass.d -MT obj/IRAncestorsPass.o
g++ -c src/CodeGen_Bash.cpp -o obj/CodeGen_Bash.o -MMD -MF obj/CodeGen_Bash.d -MT obj/CodeGen_Bash.o
g++ -c src/Parser.cpp -o obj/Parser.o -MMD -MF obj/Parser.d -MT obj/Parser.o
g++ -c src/SymbolTable.cpp -o obj/SymbolTable.o -MMD -MF obj/SymbolTable.d -MT obj/SymbolTable.o
g++ -c src/TypeChecker.cpp -o obj/TypeChecker.o -MMD -MF obj/TypeChecker.d -MT obj/TypeChecker.o
g++ -g -O0 -o bish src/bish.cpp obj/CallGraph.o obj/IR.o obj/IRVisitor.o obj/IRAncestorsPass.o obj/CodeGen_Bash.o obj/Parser.o obj/SymbolTable.o obj/TypeChecker.o
$ cd examples
$ cat fib.bish
def fib(n) {
if (n < 2) {
return 1;
}
return fib(n-1) + fib(n-2);
}
fib(15);
$ ../bish fib.bish
[1] 63707 segmentation fault ../bish fib.bish
Here's some info on my setup.
$ uname -a
Darwin Planet-X 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
Sounds good to me
The following snippet complains that newval is not defined, however it is.
def slice_lines(val, start) {
nlines = numlines(val)
if (nlines < 2) {
println("Error1.")
quit(0)
}
newval = ""
for (curr in 1 .. nlines) {
line = getline(val, curr)
# if (curr >= start) {
println("Got line: $line")
# if (curr != start) {
# newval = printf("$newval\n$chompline")
# }
}
}
return newval
}
Error:
Bish error: Undefined variable "newval"
Abort
The following program causes an error segmentation.
def array_length(arr) {
return @(echo \${#arr[@]});
}
a = [1, 2, 3, 4, 5];
println(array_length(a));
Sounds good to me
Here I propose to speak about all the standard features that will be included in Bish. It is desirable to describe the functions that are used very often in scripting.
My suggestions:
abort - display a message if something went wrong
# example
def abort(m) {
println(m);
@(exit 1);
}
Beauty can add the selected message in red.
chmod - establish certain rights to the file / folder
read - receiving data from a user
glob - retrieving files by mask
@tdenniston I can translate the documentation into Russian. Create a new page on the Wiki I did not get.
I think you need to create a folder in the repository and load transfers to her?
Currently, the following bish script:
for (i in 0 .. 10) {
print("$i ");
}
will print all numbers from 0 to 10, inclusive. The usual behavior of ranges such as these is that the lower bound is inclusive, but the upper bound is exclusive. Bish should probably match this expectation.
Currently, if you have print
statements in a function that returns a value, those print statements will form a part of the return value. This is due to the way bash return values work. For example:
def f(x) {
print("executing f: ");
return x+1;
}
assert(f(2) == 3);
This assertion will fail because the return value of f(2)
is not 3
, but executing f: 3
.
While this behavior matches the behavior of bash functions, it is not intuitive and should be fixed.
When using if, bish seems to always uses -eq for string comparisons. This makes it impossible (?) to compare strings. I wanted to write a "direxists" that made sure the dir arg wasn't empty, but couldn't do it:
def direxists(dir) {
if (dir == "") {
return false;
}
@(test -d $dir);
return success();
}
produces:
function bish_direxists () {
if [[ $1 -eq "" ]]; then
echo 0; exit;
fi;
test -d $1;
echo $(bish_success); exit;
}
But this gives an error: line 7: [[: /dirname: syntax error: operand expected (error token is "/dirname")
. Line 7 is the if with -eq on it.
Hello,
I am trying to write some utility functions since bish is strongly typed (somewhat).
def lastchar(x) {
if (x != "") {
y = @(echo -ne "$x" | tail -c 1)
x = "$y"
}
return x
}
def allbutlastchar(x) {
len = @(echo -ne "$x" | wc -c)
val = ""
if ((len != "0") and (len != "")) {
lenNeg1 = @(echo "$len-1" | bc)
temp = @(echo "$x" | head -c $lenNeg1)
val = "$temp"
}
return val
}
def str2num(x) {
val = 0
mul = 1
digit = 0
str = x
for (cond in 0 .. 1000) {
if (str == "") {
return val
}
lastc = lastchar(str)
# print(" lastc: $lastc")
str = allbutlastchar(str)
# print(" rest: $str")
if (lastc == "0") {
# do nothing
}
if (lastc == "1") {
val = val + (1 * mul)
}
if (lastc == "2") {
val = val + (2 * mul)
}
if (lastc == "3") {
val = val + (3 * mul)
}
if (lastc == "4") {
val = val + (4 * mul)
}
if (lastc == "5") {
val = val + (5 * mul)
}
if (lastc == "6") {
val = val + (6 * mul)
}
if (lastc == "7") {
val = val + (7 * mul)
}
if (lastc == "8") {
val = val + (8 * mul)
}
if (lastc == "9") {
val = val + (9 * mul)
}
# println(" value: $val")
mul = mul * 10
}
# println("final-value: $val")
return val
}
val = str2num("499")
println("Got number : $val")
I had a few issues writing this and I still don't get the correct output.
Let me know if I can help further.
Here's a messed up bit of code that causes bish to segfault:
def f(n) {
return 8(n);
}
An "invalid token type for atom" or similar error would be OK, I don't expect the code to actually work since numbers are used for argument passing in the compiled shell code.
I've been thinking of something like this for a while, but I always focused on the idea of automating the autocompletion scripts. It would be really cool to come up with a declarative syntax for defining function arguments that could be compiled into programmable completion in bash.
Here is a contrived example of how a function in bish could be annotated:
def ls(file=None, **kwargs) {
"""
@file: File= - the name of the file to ls
@-l - enable long output
@-a - include hidden files
@--longopt - longer option for example
"""
return /bin/ls file? **kwargs
}
This would enable the following behavior:
> ls <Tab>
file - the name of the file to ls
-l - enable long output
-a - include hidden files
--longopt - longer option for example
> ls -<Tab>
-l - enable long output
-a - include hidden files
--longopt - longer option for example
> ls --long<Tab>
> ls --longopt
> ls --longopt<Tab>
--longopt - longer option for example
You can see a real world example of this type of autocompletion with tmux. Start some sessions and type tmux attach-session -<Tab>
. I'm not sure if it would work to this degree in bash as I've only seen it in zsh, but it does offer some level of programmable autocompletion.
It would be nice if you could push a tag now and then, so I could write a Homebrew package! 😎
I think this is a great idea. I wonder, perhaps it may make sense to target sh
instead of bash
? afaik, sh
is more portable + found in more systems. though i'm not sure.
Bash's [[
builtin provides various extensions and improvements, include the regex-matching [[ str =~ regex ]]
.
For other shells, we can wrap it up like echo 'str' | grep -o 'regex'
and send it to an array (emulated or shell native), just like bash uses BASH_REMATCH
.
Perhaps there is some way to have a single step compile / source so that we could make .bish files executable and put a shabang at the top?
Something like :
...
And then that automatically does this when you run it:
bish < myscript.bish | bash
Or something to that effect?
Having to compile it seems like a lot of friction for quick and dirty. But it is great for deploying when you want to drop something on a server and not have to install anything (namely bish)
Is there any way to do it? I'm struggling to use awk
in my bish script.
Already tried the following combinations:
@(awk "{ print $1 }");
@(awk "{ print $$1 }");
@(awk "{ print \$1 }");
The result is the same, no matter the combination:
Parsing error: Expected variable to be a symbol near character '1', line 2
With the current code generation for bash, all variables are global. For example:
def set() {
global = 3;
}
def get() {
return global;
}
set();
println(get());
This script prints "3" when it would make more sense for it to be a compile-time error in get()
about an unknown variable.
The fix for this issue is:
global = 0;
at module/global scope.local
bash keyword during code generation.Here is a snippet that works correctly when run as a standalone bash script but fails in bash -r:
def readline() {
y = @(exec head -n 1 -)
return "$y"
}
val = readline()
println("Got $val")
This seems to me to be because of run_on
in bish.cpp
.
I propose we create a temporary file somewhere and run it using system
rather than trying to mimic the semantics of this.
Thoughts?
I'd be willing to fix this issue.
Currently, the only way to compile a script is passing an existing file as an argument:
./bish input.bish > output.bash
I think bish should be able to read a script from standard input, too:
cat input.bish | ./bish > output.bash
Why does this feature need to be added? Well, it would make bish adhere more closely to UNIX principles, making it easier to use in various scripts. But the specific reason I care is that it makes experimentation easier. After I compiled bish
, the first thing I tried was this:
echo "export x=3" | ./bish
I wanted to see what kind of boilerplate bish
adds to its output. I was disappointed that the command failed. I see no downside to changing bish
so that it works.
As discussed here: http://ubuntuforums.org/showthread.php?t=2274570
File globbing is considered one of the main benefits of shell scripts versus other scripting languages. Bish should support globbing as a first-class feature.
Example of how this might look:
for (f in *.txt) {
println("Text file: $f")
}
Seems like when functions from StdLib are pulled in, the pulling in isn't recursive. Maybe just include the lot, regardless of if they are used or not? Bloat for the win!
The following example:
if (exists("file-that-does-not-exist")) {
print("file exists");
}
gives this, which is missing bish_success function.
function bish_main () {
if [[ $(bish_exists "file-that-does-not-exist") ]]; then
bish_print "file exists";
fi;
}
function bish_exists () {
test -e $1;
echo $(bish_success); exit;
}
function bish_print () {
echo $1;
}
bish_main;
One common observation about bish is that requiring semicolons and curly braces doesn't seem like "modern syntax." The original reason why I added those requirements was to make parsing easier. However, to make bish more attractive for shell scripting, semicolons should be optional.
Statement parsing should search either for a newline character or a semicolon. Thus, if one wants to write two statements on the same line, a semicolon can be used to separate them. Semicolons at the end of a line will be allowed, but serve no purpose.
(Note there is precedent in the swift
language for this approach).
The idea: to make a function to check the types of values. For example, for the numbers, floating point numbers, or Boolean values.
This will improve the code of the programs significantly.
Should be able to do e.g. ls | grep foo
in bish.
$ bish test-userlib.bish > test-userlib.bash
Bish parsing error: Invalid token type for atom.
It's not very convenient that the "Invalid token type for atom" don't show the line number.
If you compile this file, the function println will be generated twice.
I think that it generates the assert function to initialize the standard library. Need to do accounting functions created so that they generate only once.
Bash supports lots of string manipulation:
http://tldp.org/LDP/abs/html/string-manipulation.html
Bish should unify the functionality covered in that page and provide a saner syntax.
I wrote the following script:
a = [1, 2, 3, 4];
for (u in a) {
println(u);
}
And got a bash script:
# ...
function main () {
for u in $a; do
local _0="$u";
StdLib_println "$_0";
done;
}
function StdLib_println () {
local s="$1";
echo -e "$s";
}
a=( 1 2 3 4 );
main;
But when you start getting only the first element.
Perhaps there is something wrong with the compiler.
File tests.bish
:
values = ["1.23", "2.04", "3.23"];
for (v in values) {
print("Default value: ");
print(v);
}
Result:
egor@book:~/Scripts/Bish > bish -r tests.bish
Bish error: Invalid argument type for function call in file 'tests.bish' line 5:
print(v);
...
The type checker simply fails an assertion if some statement fails to typecheck. It would be nice if these messages point to the line number of the error.
Hi tdenniston ,
Thank you for your great bish .
I find that we can override the default standard library path by setting the via BISH_STDLIB.
But I think we don't need to override it normally.And we only need to extend it.
So I suggest that add via BISH_USERLIB for this.
Best regards,
Shulei.
When you create an alias is required in the application directory to load the library.
This is awkward. You can fix this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.