Skip to content

Commit

Permalink
Implement escaping
Browse files Browse the repository at this point in the history
  • Loading branch information
klntsky committed Nov 15, 2024
1 parent ea82c48 commit ae8d5f6
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ This is an early work-in-progress. Follow [me on twitter](https://x.com/klntsky)
- [x] return error throwing to the parser
- [x] implement escaping
- [x] `[:variable]` and `[:variable=some value]`
- [ ] `[!assertion]`
- [x] `[:if ... :then ... :else ...]`
- [x] `[$ meta-prompt]`
- [x] `[:use module :param1=value1]`
Expand Down
14 changes: 14 additions & 0 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ of prompt rewriting:

Notice the double nesting of `[$` - the improved prompt will be fed back into an LLM.

# Escaping

Normally, you would not need escaping, e.g. `[:foo` will evaluate to `[:foo` as text. But if you want to specify a MetaPrompt expression literally, use `\` before the `[` character: `\[:foo]` will evaluate to `[:foo]` as text, without special meaning. You can escape `\` with another `\`, but only if it is positioned before a `[`:

`\foo` → (text `\foo`)

`\\` → (text `\\`)

`\[:foo]` → (text `[:foo]`)

`\\[:foo]` → (text `\\`) (variable `foo`)

`\[some text` -> (text `[some text`) - note that in this case the `\` character disappears, although escaping does not happen because `[some text` not a special MetaPrompt construct.

# Modules

Every `.metaprompt` file is a function.
Expand Down
18 changes: 16 additions & 2 deletions python/src/parse_metaprompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
raise Exception(f"Syntax error at line {line}:{column} - {msg}")


_pattern = r"\\([\[\\])"
_pattern = r"\\([\[\\])(\[)?"


def _escape_pattern(match):
first = match.group(1)
second = match.group(2)
if second is None:
if first == "\\":
return "\\\\"
elif first == "[":
return "["
else:
raise ValueError("Invariant violation: _escape_pattern")
else:
return match.group(1)


def _process_escaping(string):
return re.sub(_pattern, lambda match: match.group(1), string)
return re.sub(_pattern, _escape_pattern, string)


def _join_text_pieces(children):
Expand Down
18 changes: 16 additions & 2 deletions python/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def meta(exprs):
return {"type": "meta", "exprs": exprs}


def var(name):
return {"name": name, "type": "var"}


def use(module_name, parameters):
return {"type": "use", "module_name": module_name, "parameters": parameters}

Expand Down Expand Up @@ -65,14 +69,24 @@ def test_escaping_2():
assert result["exprs"] == [t("[:foo]")]


def test_escaping_2_1():
result = parse_metaprompt("\\\\[:foo]")
assert result["exprs"] == [t("\\\\"), var("foo")]


def test_escaping_2_2():
result = parse_metaprompt("\\\\")
assert result["exprs"] == [t("\\\\")]


def test_escaping_3():
result = parse_metaprompt("\\[:foo")
assert result["exprs"] == [t("[:foo")]


def test_escaping_4():
result = parse_metaprompt("\\\\[")
assert result["exprs"] == [t("\\[")]
assert result["exprs"] == [t("\\\\[")]


def test_escaping_5():
Expand All @@ -92,7 +106,7 @@ def test_absence_of_comment():

def test_meta():
result = parse_metaprompt("[:test]")
assert result["exprs"] == [{"name": "test", "type": "var"}]
assert result["exprs"] == [var("test")]


def test_meta_text():
Expand Down

0 comments on commit ae8d5f6

Please sign in to comment.