Skip to content

Commit 8cdb9d0

Browse files
Merge pull request #54 from yassinebenaid/dev
Bug fixes and docs improvment
2 parents bc31b1c + 36ed9a9 commit 8cdb9d0

File tree

8 files changed

+215
-96
lines changed

8 files changed

+215
-96
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ Technically speaking, **Bunster** is not a complete compiler, But rather a **Tra
2525
- **Different Shells support**: Bunster currently aims to be compatible `Bash` as a starting move. then other popular shells in future.
2626
- **Security**: as you may guess, humans cannot read machine code, so why not to compile your scripts to such format.
2727
- **Modules**: something shell scripts lack is a module system, people want to share their code to be used by others, but the infrastructure doesn't allow them. Well, **Bunster** introduces a module system that allow you to publish your scripts as a modules consumed by other users.
28-
- **Performance**: the shell (including bash, zsh ...etc) rely on forking to run your scripts, this means, if you have a script of 3 commands, the shell will have to fork it self 3 times to run each command. This allows the shell to play with file descriptors and other resouces freely. But adds a lot of performance overhead. **Bunster** runs your entire scripts in a single process. and uses [goroutines](https://go.dev/tour/concurrency/1) for background commands. **Bunster** even has its own file descripor system managed by it's runtime. this means less syscalls, thus, better performance.
28+
- **Performance**: You should't be concerned about performance that much, But at least scripts compiled by **Bunster** will not suffer to parse and interpret
29+
your scripts everytime you run them.
2930

3031
> [!WARNING]
31-
> This project is in its early phase of development and is not yet ready for production. Not all features are implemented yet. But, plenty of them are already working. such as simple command invokation, redirections, environment variables and more.
32+
> This project is in its early phase of development and is not yet ready for production. Not all features are implemented yet. But, plenty of them are.[see what features are features so far](https://bunster.netlify.app/supported-features.html) such as simple command invokation, redirections, environment variables and more.
3233
3334
### Versionning
3435
**Bunster** follows [SemVer](https://semver.org/) system for release versionning. On each `v0.x.0` release, You would expect adding support for new features (can be new shell feature, improvement in the build process, some custom features ...etc.) . On each `v0.N.x` release, you would expect bug fixes and documentation enhancments.

docs/.vitepress/config.mts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ export default defineConfig({
1010
nav: [
1111
{ text: "Documentation", link: "/quick-start" },
1212
{ text: "Installation", link: "/installation" },
13+
{ text: "Maintainers", link: "/maintainers" },
1314
],
14-
15+
logo: "/logo.png",
16+
search: {
17+
provider: "local",
18+
},
1519
sidebar: [
1620
{
1721
items: [
1822
{ text: "Quick Start", link: "/quick-start" },
1923
{ text: "Installation", link: "/installation" },
24+
{ text: "Supported Features", link: "/supported-features" },
2025
],
2126
},
2227
],
@@ -29,9 +34,17 @@ export default defineConfig({
2934
message: "Released under the GPLv3 License.",
3035
copyright: "Copyright © 2024-present Yassine Benaid",
3136
},
37+
editLink: {
38+
pattern:
39+
"https://github.com/yassinebenaid/bunster/edit/master/docs/:path",
40+
},
3241
},
3342
head: [
3443
["link", { rel: "manifest", href: "/site.webmanifest" }],
3544
["link", { rel: "icon", type: "image/x-icon", href: "/favicon.ico" }],
3645
],
46+
lastUpdated: true,
47+
sitemap: {
48+
hostname: "https://bunster.netlify.app",
49+
},
3750
});

docs/maintainers.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
sidebar: false
3+
---
4+
5+
<script setup>
6+
import { VPTeamMembers } from 'vitepress/theme'
7+
8+
const members = [
9+
{
10+
avatar: 'https://www.github.com/yassinebenaid.png',
11+
name: 'Yassine Benaid',
12+
title: 'Creator',
13+
links: [
14+
{ icon: 'github', link: 'https://github.com/yassinebenaid' },
15+
{ icon: 'linkedin', link: 'https://www.linkedin.com/in/yassinebenaid' },
16+
{ icon: 'reddit', link: 'https://www.reddit.com/user/yassinebenaid' }
17+
]
18+
},
19+
]
20+
</script>
21+
22+
# Maintainers
23+
**Bunster** is an open source project maintained and driven by the community, But we have a dedicated team
24+
that takes the final decision on contributions and feature requests. And keeps contact with the rest of the community to ensure a healthy and friendly
25+
environment for everyone.
26+
27+
Say hello to our awesome team.
28+
29+
<VPTeamMembers size="small" :members="members" />

docs/supported-features.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Supported Features
2+
This page lists the features and syntax supported by **Bunster**. you must consider any feature that is not mentioned here
3+
as work-in-progress and as not-yet-supported.
4+
5+
6+
## Simple commands
7+
```shell
8+
command argument 'argument' "argument" $VARIABLE
9+
```
10+
11+
## Redirections
12+
### Output redirection
13+
```shell
14+
command >file.txt >|file.txt >>file.txt &>file.txt &>>file.txt
15+
```
16+
### Input redirection
17+
```shell
18+
command <file.txt <<<"foo bar"
19+
```
20+
### File descriptor duplication and closing
21+
```shell
22+
command 2>&3 3>&4- 3>&- 2>&-
23+
```
24+
### Opening files for reading and writing
25+
```shell
26+
command <>file.txt 3<>file.txt
27+
```
28+
29+
::: tip
30+
Unlick bash, you are not limited to only use file descriptors between 0 to 9. Feel free to use any valid 64-bit integer number. (learn why TODO: add this link here)
31+
:::
32+
33+
## Passing shell parameters as environment to commands
34+
```shell
35+
key=value key2="value" command
36+
```
37+
38+
## Pipelines
39+
```shell
40+
command | command2 | command3
41+
```

generator/generator.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ func (g *generator) handleExpression(expression ast.Expression) ir.Instruction {
8989
return ir.String(v)
9090
case ast.Var:
9191
return ir.ReadVar(v)
92+
case ast.QuotedString:
93+
var concat ir.Concat
94+
for _, expr := range v {
95+
concat = append(concat, g.handleExpression(expr))
96+
}
97+
return concat
98+
case ast.UnquotedString:
99+
var concat ir.Concat
100+
for _, expr := range v {
101+
concat = append(concat, g.handleExpression(expr))
102+
}
103+
return concat
92104
default:
93105
panic(fmt.Sprintf("unhandled expression type (%T)", expression))
94106
}

ir/ir.go

Lines changed: 13 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ func (s String) togo() string {
7070
return fmt.Sprintf("`%s`", s)
7171
}
7272

73+
type Concat []Instruction
74+
75+
func (c Concat) togo() string {
76+
var str string
77+
for i, ins := range c {
78+
str += ins.togo()
79+
if i < len(c)-1 {
80+
str += "+\n"
81+
}
82+
}
83+
return str
84+
}
85+
7386
type Literal string
7487

7588
func (s Literal) togo() string {
@@ -114,98 +127,6 @@ func (r StartCommand) togo() string {
114127
`, r)
115128
}
116129

117-
const (
118-
FLAG_READ = "STREAM_FLAG_READ"
119-
FLAG_WRITE = "STREAM_FLAG_WRITE"
120-
FLAG_RW = "STREAM_FLAG_RW"
121-
FLAG_APPEND = "STREAM_FLAG_APPEND"
122-
)
123-
124-
type OpenStream struct {
125-
Name string
126-
Target Instruction
127-
Mode string
128-
}
129-
130-
func (of OpenStream) togo() string {
131-
return fmt.Sprintf(
132-
`%s, err := runtime.OpenStream(%s, runtime.%s)
133-
if err != nil {
134-
shell.HandleError(err)
135-
return
136-
}
137-
`, of.Name, of.Target.togo(), of.Mode)
138-
}
139-
140-
type NewStringStream struct {
141-
Target Instruction
142-
}
143-
144-
func (of NewStringStream) togo() string {
145-
return fmt.Sprintf("runtime.NewStringStream(%s)", of.Target.togo())
146-
}
147-
148-
type CloneFDT string
149-
150-
func (c CloneFDT) togo() string {
151-
return fmt.Sprintf(
152-
`%s, err := shell.CloneFDT()
153-
if err != nil {
154-
shell.HandleError(err)
155-
return
156-
}
157-
defer %s.Destroy()
158-
`, c, c)
159-
}
160-
161-
type AddStream struct {
162-
FDT string
163-
Fd string
164-
StreamName string
165-
}
166-
167-
func (as AddStream) togo() string {
168-
return fmt.Sprintf("%s.Add(`%s`, %s)\n", as.FDT, as.Fd, as.StreamName)
169-
}
170-
171-
type GetStream struct {
172-
FDT string
173-
Fd Instruction
174-
}
175-
176-
func (as GetStream) togo() string {
177-
return fmt.Sprintf(`%s.Get(%s)`, as.FDT, as.Fd.togo())
178-
}
179-
180-
type DuplicateStream struct {
181-
FDT string
182-
Old string
183-
New Instruction
184-
}
185-
186-
func (as DuplicateStream) togo() string {
187-
return fmt.Sprintf(
188-
`if err := %s.Duplicate("%s", %s); err != nil {
189-
shell.HandleError(err)
190-
return
191-
}
192-
`, as.FDT, as.Old, as.New.togo())
193-
}
194-
195-
type CloseStream struct {
196-
FDT string
197-
Fd Instruction
198-
}
199-
200-
func (c CloseStream) togo() string {
201-
return fmt.Sprintf(
202-
`if err := %s.Close(%s); err != nil {
203-
shell.HandleError(err)
204-
return
205-
}
206-
`, c.FDT, c.Fd.togo())
207-
}
208-
209130
type Closure struct {
210131
Body []Instruction
211132
}

ir/stream.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package ir
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
const (
8+
FLAG_READ = "STREAM_FLAG_READ"
9+
FLAG_WRITE = "STREAM_FLAG_WRITE"
10+
FLAG_RW = "STREAM_FLAG_RW"
11+
FLAG_APPEND = "STREAM_FLAG_APPEND"
12+
)
13+
14+
type OpenStream struct {
15+
Name string
16+
Target Instruction
17+
Mode string
18+
}
19+
20+
func (of OpenStream) togo() string {
21+
return fmt.Sprintf(
22+
`%s, err := runtime.OpenStream(%s, runtime.%s)
23+
if err != nil {
24+
shell.HandleError(err)
25+
return
26+
}
27+
`, of.Name, of.Target.togo(), of.Mode)
28+
}
29+
30+
type NewStringStream struct {
31+
Target Instruction
32+
}
33+
34+
func (of NewStringStream) togo() string {
35+
return fmt.Sprintf("runtime.NewStringStream(%s)", of.Target.togo())
36+
}
37+
38+
type CloneFDT string
39+
40+
func (c CloneFDT) togo() string {
41+
return fmt.Sprintf(
42+
`%s, err := shell.CloneFDT()
43+
if err != nil {
44+
shell.HandleError(err)
45+
return
46+
}
47+
defer %s.Destroy()
48+
`, c, c)
49+
}
50+
51+
type AddStream struct {
52+
FDT string
53+
Fd string
54+
StreamName string
55+
}
56+
57+
func (as AddStream) togo() string {
58+
return fmt.Sprintf("%s.Add(`%s`, %s)\n", as.FDT, as.Fd, as.StreamName)
59+
}
60+
61+
type GetStream struct {
62+
FDT string
63+
Fd Instruction
64+
}
65+
66+
func (as GetStream) togo() string {
67+
return fmt.Sprintf(`%s.Get(%s)`, as.FDT, as.Fd.togo())
68+
}
69+
70+
type DuplicateStream struct {
71+
FDT string
72+
Old string
73+
New Instruction
74+
}
75+
76+
func (as DuplicateStream) togo() string {
77+
return fmt.Sprintf(
78+
`if err := %s.Duplicate("%s", %s); err != nil {
79+
shell.HandleError(err)
80+
return
81+
}
82+
`, as.FDT, as.Old, as.New.togo())
83+
}
84+
85+
type CloseStream struct {
86+
FDT string
87+
Fd Instruction
88+
}
89+
90+
func (c CloseStream) togo() string {
91+
return fmt.Sprintf(
92+
`if err := %s.Close(%s); err != nil {
93+
shell.HandleError(err)
94+
return
95+
}
96+
`, c.FDT, c.Fd.togo())
97+
}

runtime/stream.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func NewStringStream(s string) Stream {
5858
type FileDescriptorTable map[string]Stream
5959

6060
func (fdt FileDescriptorTable) Add(fd string, stream Stream) {
61-
// If this stream is already open, we need to close it. otherwise, Its handler will be loats and leak.
61+
// If this stream is already open, we need to close it. otherwise, Its handler will be lost and leak.
6262
// This is related to pipelines in particular. when instantiating a new pipeline, we add its ends to the FDT. but if
6363
// a redirection happened afterwards, it will cause the pipline handler to be lost and kept open.
6464
if fdt[fd] != nil {
@@ -82,6 +82,11 @@ func (fdt FileDescriptorTable) Duplicate(newfd, oldfd string) error {
8282
if stream, ok := fdt[oldfd]; !ok {
8383
return fmt.Errorf("trying to duplicate bad file descriptor: %s", oldfd)
8484
} else {
85+
// If the new fd is already open, we need to close it. otherwise, Its handler will be lost and leak. and remain open forever.
86+
if fdt[newfd] != nil {
87+
_ = fdt[newfd].Close() // error here is not important.
88+
}
89+
8590
switch stream := stream.(type) {
8691
case *stringStream:
8792
newbuf := &bytes.Buffer{}

0 commit comments

Comments
 (0)