From bc7482949344201f8c7e350813b265e29d8728fe Mon Sep 17 00:00:00 2001 From: odino Date: Fri, 28 Dec 2018 18:03:33 +0400 Subject: [PATCH] Fixed string interpolation in system commands, closes #81 --- docs/syntax/system-commands.md | 8 ++++++++ evaluator/evaluator.go | 18 +++++++++++++++++- evaluator/evaluator_test.go | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/syntax/system-commands.md b/docs/syntax/system-commands.md index 8495b7ef..6353a781 100644 --- a/docs/syntax/system-commands.md +++ b/docs/syntax/system-commands.md @@ -42,6 +42,14 @@ x = $(cat /proc/$file) echo(x) # processor: 0\nvendor_id: GenuineIntel... ``` +and if you need `$` literals in your command, you +simply need to escape them with a `\`: + +``` bash +$(echo $PWD) # "" since the ABS variable PWD doesn't exist +$(echo \$PWD) # "/go/src/github.com/abs-lang/abs" +``` + Currently, commands need to be on their own line, meaning that you will not be able to have additional code on the same line. This will throw an error: diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 5f4ce78b..a15399df 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -874,8 +874,24 @@ func evalHashIndexExpression(hash, index object.Object) object.Object { } func evalCommandExpression(cmd string, env *object.Environment) object.Object { - re := regexp.MustCompile("\\$([a-zA-Z_]{1,})") + // Match all strings preceded by + // a $ or a \$ + re := regexp.MustCompile("(\\\\)?\\$([a-zA-Z_]{1,})") cmd = re.ReplaceAllStringFunc(cmd, func(m string) string { + // If the string starts with a backslash, + // that's an escape, so we should replace + // it with the remaining portion of the match. + // \$VAR becomes $VAR + if string(m[0]) == "\\" { + return m[1:] + } + + // If the string starts with $, then + // it's an interpolation. Let's + // replace $VAR with the variable + // named VAR in the ABS' environment. + // If the variable is not found, we + // just dump an empty string v, ok := env.Get(m[1:]) if !ok { diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 93346bdf..d0f4ef1c 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -1037,6 +1037,7 @@ func TestCommand(t *testing.T) { {`$(echo -n "123")`, "123"}, {`$(echo -n hello world)`, "hello world"}, {`$(echo hello world | xargs echo -n)`, "hello world"}, + {`$(echo \$CONTEXT)`, "abs"}, } for _, tt := range tests {