[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[sc-users] Re: string formatting notation



Sorry to prolong this, but there was a mistake in the preprocessor...
corrected here.

hjh

(
var
convertFStrings = { |code|
	var stream = CollStream(code), out = String.new, ch, closeQuote;
	while {
		ch = stream.next;
		ch.notNil
	} {
		case
		{ ch == $f and: { stream.peek == $" } } {
			stream.next;  // swallow quote
			out = out ++ parseFString.(stream);
		}
		{ ch == $" or: { ch == $' } } {  // scan a whole normal string/symbol
literal, with escapes
			closeQuote = ch;
			out = out ++ ch;
			while {
				ch = stream.next;
				ch.notNil and: { ch != closeQuote }
			} {
				if(ch == $\\) {
					out = out ++ ch ++ stream.next;  // escape, esp. for quotes
				} {
					out = out ++ ch;
				}
			};
			if(ch.notNil) { out = out ++ ch };
		}
		{
			out = out ++ ch;
		};
	};
	out;
},
parseFString = { |stream|
	// assumes 'f"' is already scanned; return: code converted to
"str".format(...)
	var start = stream.pos, list = List.new, formatStr = String.new, out, ch;
	while {
		ch = stream.next;
		ch.notNil and: { ch != $" }
	} {
		if(ch == ${ and: { stream.peek == ${ }) {
			stream.next;  // swallow second brace
			parseOneExpression.(stream, list);
			formatStr = formatStr ++ "%";
		} {
			formatStr = formatStr ++ ch;
		};
	};
	if(ch.isNil) {
		Error("open-ended f-string: %".format(stream.collection[start .. start +
20])).throw;
	};
	if(list.size >= 1) {  // .format only if there's something to format
		out = CollStream.new;
		out << $" << formatStr << $" << ".format(";
		list.do { |expr, i|
			if(i > 0) { out << ", " };
			out << expr;
		};
		out << ")";
		out.collection
	} {
		// -1 -- we need the opening quote, and don't include .next char
		stream.collection[start - 1.. stream.pos - 1]
	}
},
parseOneExpression = { |stream, list|
	// assumes '{{' is already scanned; result: item added to list
	var start = stream.pos, out = String.new, ch;
	while {
		ch = stream.next;
		ch.notNil and: { ch != $} or: { stream.peek != $} } }
	} {
		// check for nested f-string
		if(ch == $f and: { stream.peek == $" }) {
			stream.next;  // swallow quote
			out = out ++ parseFString.(stream);
		} {
			out = out ++ ch;
		};
	};
	if(ch.isNil) {
		Error("open-ended string interpolation argument: %".format(
			stream.collection[start .. start + 20]
		)).throw;
	};
	list.add(out);
	stream.next;  // scan second brace
	stream
};

// some tests

c = CollStream("abc}}xyz");
l = List.new;
parseOneExpression.(c, l);
l.debug("list, expected [ \"abc\" ]");
c.collection[c.pos..c.pos+5].debug("stream state, expected \"xyz\"");

c = CollStream("abc = {{abc}}\"; xyz");
parseFString.(c).debug("parseFString test");

c = "var abc = 10.rand; f\"abc = {{abc ++ f\"nested string
{{xyz}}\"}}\".postln;";
convertFStrings.(c).debug("nested conversion");

c = "\"normal \\\"string\\\" ending with f\".postln";
convertFStrings.(c).debug("escaped \"quotes\" and closing f");

c = "'abcdef\"xyz'";
convertFStrings.(c).debug("weird symbol");

try {
	convertFStrings.("f\"{{abc}xyz\"")
} { |error|
	if(error.errorString.beginsWith("ERROR: open-ended string interpolation
argument")) {
		"open-ended string interpolation argument detected OK".debug;
	} {
		error.throw;
	}
};

try {
	convertFStrings.("f\"{{abc}}xyz; 123")
} { |error|
	if(error.errorString.beginsWith("ERROR: open-ended f-string")) {
		"open-ended f-string detected OK".debug;
	} {
		error.throw;
	}
};

thisProcess.interpreter.preProcessor = convertFStrings;
)



--
Sent from: http://new-supercollider-mailing-lists-forums-use-these.2681727.n2.nabble.com/SuperCollider-Users-New-Use-this-f2676391.html

_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: https://listarc.bham.ac.uk/marchives/sc-users/
search: https://listarc.bham.ac.uk/lists/sc-users/search/