Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: TypeShell Linux
on:
push:
branches:
- main
- '*'
pull_request:
branches:
- main
- '*'
release:
types:
- created
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,10 @@ print(s[0]) // Prints "Hello".
print(s[1]) // Prints "".
print(s[2]) // Prints "World".
```

## Visual Studio Code
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.
- Open VSCode.
- Go to File -> Preferences -> Settings.
- Seach for "file associations".
- Add "*.tsh" to the list and associate it with Go.
43 changes: 25 additions & 18 deletions converters/bash/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ func New() *converter {
}

func (c *converter) StringToString(value string) string {
// Replace "\\n" with "\n".
return strings.ReplaceAll(value, "\\n", "\n")
return value
}

func (c *converter) Dump() (string, error) {
Expand Down Expand Up @@ -81,14 +80,16 @@ func (c *converter) ProgramEnd() error {
"while [ ${_i} -lt ${_l} ]; do",
fmt.Sprintf("local _v=%s", c.sliceEvaluationString("${2}", "${_i}")),
c.sliceAssignmentString("${_n}", "${_i}", "${_v}", false),
"_i=$(expr ${_i} + 1)",
"_i=$((${_i}+1))",
"done",
)
}

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

func (c *converter) VarAssignment(name string, value string, global bool) error {
length := len(value)

if length > 0 {
if string(value[length-1]) != "\"" {
value = fmt.Sprintf("%s\"", value)
}
if string(value[0]) != "\"" {
value = fmt.Sprintf("\"%s", value)
}
}
c.addLine(fmt.Sprintf("%s=%s", c.varName(name, global), value))
c.addLine(c.varAssignmentString(name, value, global))
return nil
}

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

for i, param := range params {
c.VarAssignment(param, fmt.Sprintf("$%d", i+1), false)
s := c.varAssignmentString(param, fmt.Sprintf("$%d", i+1), false)
c.addLine(fmt.Sprintf("local %s", s))
}
return nil
}
Expand Down Expand Up @@ -279,7 +271,7 @@ func (c *converter) BinaryOperation(left string, operator parser.BinaryOperator,
default:
return notAllowedError()
}
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).
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).
case parser.DATA_TYPE_STRING:
switch operator {
case parser.BINARY_OPERATOR_ADDITION:
Expand Down Expand Up @@ -419,7 +411,8 @@ func (c *converter) SliceLen(name string, valueUsed bool) (string, error) {
func (c *converter) StringSubscript(value string, startIndex string, endIndex string, valueUsed bool) (string, error) {
helper := c.nextHelperVar()

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

return c.varEvaluationString(helper, false), nil
Expand Down Expand Up @@ -559,6 +552,20 @@ func (c *converter) varName(name string, global bool) string {
return name
}

func (c *converter) varAssignmentString(name string, value string, global bool) string {
length := len(value)

if length > 0 {
if string(value[length-1]) != `"` {
value = fmt.Sprintf(`%s"`, value)
}
if string(value[0]) != `"` {
value = fmt.Sprintf(`"%s`, value)
}
}
return fmt.Sprintf("%s=%s", c.varName(name, global), value)
}

func (c *converter) varEvaluationString(name string, global bool) string {
return fmt.Sprintf("${%s}", c.varName(name, global))
}
Expand Down
2 changes: 1 addition & 1 deletion converters/batch/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func (c *converter) ProgramEnd() error {
c.addHelper("string length", stringLengthHelper,
"set _l=0",
":_stlhl",
fmt.Sprintf(`if "!%s:~%%_l%%!" equ "" goto :_stlhle`, funcArgVar(0)), // https://www.geeksforgeeks.org/batch-script-string-length/
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/
`set /A "_l=%_l%+1"`,
"goto :_stlhl",
":_stlhle",
Expand Down
10 changes: 10 additions & 0 deletions examples/find_linux.tsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "strings" // Import standard library "strings".

pattern := input("Find pattern: ") // Ask user for pattern input.
filesString, stderr, code := @ls("-1") | @grep(pattern) // Make program calls.
files := strings.Split(filesString, "\n") // Split files list at newline.

// Iterate files.
for i, f := range files {
print(i, f)
}
10 changes: 10 additions & 0 deletions examples/find_windows.tsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "strings" // Import standard library "strings".

pattern := input("Find pattern: ") // Ask user for pattern input.
filesString, stderr, code := @dir("/b") | @findstr(pattern) // Make program calls.
files := strings.Split(filesString, "\n") // Split files list at newline.

// Iterate files.
for i, f := range files {
print(i, f)
}
8 changes: 4 additions & 4 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func Tokenize(source string) ([]Token, error) {
ogRow := row
ogColumn := column

if c0 == "\"" {
if raw := c0 == "`"; raw || c0 == `"` {
// Evaluate string.
str := ""
i++
Expand All @@ -257,7 +257,7 @@ func Tokenize(source string) ([]Token, error) {
c0 = char(source, i)
appended := false

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

Expand All @@ -267,7 +267,7 @@ func Tokenize(source string) ([]Token, error) {
str += parsed
i += len(match)
appended = true
} else if c0 == "\"" {
} else if (raw && c0 == "`") || (!raw && c0 == `"`) {
// Detected string end.
i++
token = newToken(str, STRING_LITERAL, ogRow, ogColumn)
Expand Down Expand Up @@ -354,7 +354,7 @@ func Tokenize(source string) ([]Token, error) {

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