Skip to content

Commit 56ac6c0

Browse files
authored
V0.1.1 (#34)
* Add local keyword to local variables (Bash) * Trigger workflow on any branch * Add VSCode syntax highlighting workaround description * Improve strings * Fix negation handling (#30) * Add raw string support (#31) * Add support for single variable in for-range loop (#29) * Fix len on empty string leads to endless loop (Batch) (#32) * Implement super inperformant version of strings.Split * Fix substring newline handling (Bash) * Replace expr by double parentheses (Bash) * Implement find example for Windows and Linux
1 parent d515d04 commit 56ac6c0

12 files changed

Lines changed: 248 additions & 86 deletions

File tree

.github/workflows/workflow.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ name: TypeShell Linux
33
on:
44
push:
55
branches:
6-
- main
6+
- '*'
77
pull_request:
88
branches:
9-
- main
9+
- '*'
1010
release:
1111
types:
1212
- created

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,10 @@ print(s[0]) // Prints "Hello".
287287
print(s[1]) // Prints "".
288288
print(s[2]) // Prints "World".
289289
```
290+
291+
## Visual Studio Code
292+
There is no extension for VSCode yet. However, since the code is very Go-like, adding the ".tsh" extension to the settings should serve as a first workaround.
293+
- Open VSCode.
294+
- Go to File -> Preferences -> Settings.
295+
- Seach for "file associations".
296+
- Add "*.tsh" to the list and associate it with Go.

converters/bash/converter.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ func New() *converter {
3434
}
3535

3636
func (c *converter) StringToString(value string) string {
37-
// Replace "\\n" with "\n".
38-
return strings.ReplaceAll(value, "\\n", "\n")
37+
return value
3938
}
4039

4140
func (c *converter) Dump() (string, error) {
@@ -81,14 +80,16 @@ func (c *converter) ProgramEnd() error {
8180
"while [ ${_i} -lt ${_l} ]; do",
8281
fmt.Sprintf("local _v=%s", c.sliceEvaluationString("${2}", "${_i}")),
8382
c.sliceAssignmentString("${_n}", "${_i}", "${_v}", false),
84-
"_i=$(expr ${_i} + 1)",
83+
"_i=$((${_i}+1))",
8584
"done",
8685
)
8786
}
8887

8988
if c.stringSubscriptHelperRequired {
9089
c.addHelper("substring", "_ssh",
91-
"echo \"${1}\" | cut -c $(expr ${2} \\+ 1)-$(expr ${3} \\+ 1)", // Cut index starts at 1, therefore 1 must be added to 0-based subscript.
90+
`_ls=$((${2}))`,
91+
`_ll=$(((${3}-${2})+1))`,
92+
`_ret="${1:${_ls}:${_ll}}"`,
9293
)
9394
}
9495
return nil
@@ -99,17 +100,7 @@ func (c *converter) VarDefinition(name string, value string, global bool) error
99100
}
100101

101102
func (c *converter) VarAssignment(name string, value string, global bool) error {
102-
length := len(value)
103-
104-
if length > 0 {
105-
if string(value[length-1]) != "\"" {
106-
value = fmt.Sprintf("%s\"", value)
107-
}
108-
if string(value[0]) != "\"" {
109-
value = fmt.Sprintf("\"%s", value)
110-
}
111-
}
112-
c.addLine(fmt.Sprintf("%s=%s", c.varName(name, global), value))
103+
c.addLine(c.varAssignmentString(name, value, global))
113104
return nil
114105
}
115106

@@ -127,7 +118,8 @@ func (c *converter) FuncStart(name string, params []string, returnTypes []parser
127118
c.addLine(fmt.Sprintf("%s() {", name))
128119

129120
for i, param := range params {
130-
c.VarAssignment(param, fmt.Sprintf("$%d", i+1), false)
121+
s := c.varAssignmentString(param, fmt.Sprintf("$%d", i+1), false)
122+
c.addLine(fmt.Sprintf("local %s", s))
131123
}
132124
return nil
133125
}
@@ -279,7 +271,7 @@ func (c *converter) BinaryOperation(left string, operator parser.BinaryOperator,
279271
default:
280272
return notAllowedError()
281273
}
282-
c.VarAssignment(helper, fmt.Sprintf("$(expr %s \\%s %s)", left, operator, right), false) // Backslash is required for * operator to prevent pattern expansion (https://www.shell-tips.com/bash/math-arithmetic-calculation/#using-the-expr-command-line).
274+
c.VarAssignment(helper, fmt.Sprintf("$((%s%s%s))", left, operator, right), false) // Backslash is required for * operator to prevent pattern expansion (https://www.shell-tips.com/bash/math-arithmetic-calculation/#using-the-expr-command-line).
283275
case parser.DATA_TYPE_STRING:
284276
switch operator {
285277
case parser.BINARY_OPERATOR_ADDITION:
@@ -419,7 +411,8 @@ func (c *converter) SliceLen(name string, valueUsed bool) (string, error) {
419411
func (c *converter) StringSubscript(value string, startIndex string, endIndex string, valueUsed bool) (string, error) {
420412
helper := c.nextHelperVar()
421413

422-
c.VarAssignment(helper, fmt.Sprintf("$(_ssh \"%s\" %s %s)", value, startIndex, endIndex), false) // https://www.baeldung.com/linux/bash-substring#1-using-thecut-command
414+
c.addLine(fmt.Sprintf(`_ssh "%s" %s %s`, value, startIndex, endIndex))
415+
c.VarAssignment(helper, c.varEvaluationString("_ret", true), false) // https://www.baeldung.com/linux/bash-substring#1-using-thecut-command
423416
c.stringSubscriptHelperRequired = true
424417

425418
return c.varEvaluationString(helper, false), nil
@@ -559,6 +552,20 @@ func (c *converter) varName(name string, global bool) string {
559552
return name
560553
}
561554

555+
func (c *converter) varAssignmentString(name string, value string, global bool) string {
556+
length := len(value)
557+
558+
if length > 0 {
559+
if string(value[length-1]) != `"` {
560+
value = fmt.Sprintf(`%s"`, value)
561+
}
562+
if string(value[0]) != `"` {
563+
value = fmt.Sprintf(`"%s`, value)
564+
}
565+
}
566+
return fmt.Sprintf("%s=%s", c.varName(name, global), value)
567+
}
568+
562569
func (c *converter) varEvaluationString(name string, global bool) string {
563570
return fmt.Sprintf("${%s}", c.varName(name, global))
564571
}

converters/batch/converter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (c *converter) ProgramEnd() error {
224224
c.addHelper("string length", stringLengthHelper,
225225
"set _l=0",
226226
":_stlhl",
227-
fmt.Sprintf(`if "!%s:~%%_l%%!" equ "" goto :_stlhle`, funcArgVar(0)), // https://www.geeksforgeeks.org/batch-script-string-length/
227+
fmt.Sprintf(`if "!%s!" equ "" (goto :_stlhle) else if "!%s:~%%_l%%!" equ "" goto :_stlhle`, funcArgVar(0), funcArgVar(0)), // https://www.geeksforgeeks.org/batch-script-string-length/
228228
`set /A "_l=%_l%+1"`,
229229
"goto :_stlhl",
230230
":_stlhle",

examples/find_linux.tsh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import "strings" // Import standard library "strings".
2+
3+
pattern := input("Find pattern: ") // Ask user for pattern input.
4+
filesString, stderr, code := @ls("-1") | @grep(pattern) // Make program calls.
5+
files := strings.Split(filesString, "\n") // Split files list at newline.
6+
7+
// Iterate files.
8+
for i, f := range files {
9+
print(i, f)
10+
}

examples/find_windows.tsh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import "strings" // Import standard library "strings".
2+
3+
pattern := input("Find pattern: ") // Ask user for pattern input.
4+
filesString, stderr, code := @dir("/b") | @findstr(pattern) // Make program calls.
5+
files := strings.Split(filesString, "\n") // Split files list at newline.
6+
7+
// Iterate files.
8+
for i, f := range files {
9+
print(i, f)
10+
}

lexer/lexer.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func Tokenize(source string) ([]Token, error) {
248248
ogRow := row
249249
ogColumn := column
250250

251-
if c0 == "\"" {
251+
if raw := c0 == "`"; raw || c0 == `"` {
252252
// Evaluate string.
253253
str := ""
254254
i++
@@ -257,7 +257,7 @@ func Tokenize(source string) ([]Token, error) {
257257
c0 = char(source, i)
258258
appended := false
259259

260-
if match := regexp.MustCompile(`^\\.`).FindString(source[i:]); match != "" {
260+
if match := regexp.MustCompile(`^\\.`).FindString(source[i:]); !raw && match != "" {
261261
// Convert escaped character to be a control character (https://pkg.go.dev/strconv#Unquote).
262262
parsed, err := strconv.Unquote(fmt.Sprintf(`"%s"`, match))
263263

@@ -267,7 +267,7 @@ func Tokenize(source string) ([]Token, error) {
267267
str += parsed
268268
i += len(match)
269269
appended = true
270-
} else if c0 == "\"" {
270+
} else if (raw && c0 == "`") || (!raw && c0 == `"`) {
271271
// Detected string end.
272272
i++
273273
token = newToken(str, STRING_LITERAL, ogRow, ogColumn)
@@ -354,7 +354,7 @@ func Tokenize(source string) ([]Token, error) {
354354

355355
// If still no token has been found, exit with error.
356356
if token.tokenType == UNKNOWN {
357-
err = fmt.Errorf("unknown token \"%s\" at position %d", c0, i)
357+
err = fmt.Errorf(`unknown token "%s" at position %d`, c0, i)
358358
break
359359
} else if slices.Contains([]TokenType{SPACE, COMMENT}, token.tokenType) {
360360
// Ignore spaces and comments for now.

0 commit comments

Comments
 (0)