Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compile / decompile emojis #7861

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
18 changes: 18 additions & 0 deletions pxtblocks/blocklycompiler.ts
Expand Up @@ -1214,10 +1214,26 @@ namespace pxt.blocks {
return mkCallWithCallback(e, "basic", "forever", [], body);
}

let PICTOGRAPHIC_REGEX: RegExp;
try { // Some browsers do not support unicode property escape, in which case we can just use _ replacement
PICTOGRAPHIC_REGEX = new RegExp("\\p{Extended_Pictographic}", "ug")
} catch {}
export function escapePictographic(name: string) {
if (PICTOGRAPHIC_REGEX) {
return name.replace(
PICTOGRAPHIC_REGEX,
s => `E${s.codePointAt(0).toString(16)}X`
);
}
return name;
}

// convert to javascript friendly name
export function escapeVarName(name: string, e: Environment, isFunction = false): string {
if (!name) return '_';

name = escapePictographic(name);

if (isFunction) {
if (e.renames.oldToNewFunctions[name]) {
return e.renames.oldToNewFunctions[name];
Expand Down Expand Up @@ -2348,6 +2364,8 @@ namespace pxt.blocks {
function escapeVarName(originalName: string): string {
if (!originalName) return '_';

originalName = escapePictographic(originalName);

let n = ts.pxtc.escapeIdentifier(originalName);

if (e.renames.takenNames[n] || nameIsTaken(n, current, originalName)) {
Expand Down
15 changes: 11 additions & 4 deletions pxtcompiler/emitter/decompiler.ts
Expand Up @@ -773,7 +773,7 @@ ${output}</xml>`;
mChildren.forEach(c => {
write(`<${c.nodeName} `, "");
Object.keys(c.attributes).forEach(attrName => {
write(`${attrName}="${c.attributes[attrName]}" `, "");
write(`${attrName}="${U.htmlEscape(c.attributes[attrName])}" `, "");
});
write("/>");
});
Expand Down Expand Up @@ -2536,10 +2536,10 @@ ${output}</xml>`;
if (renameMap) {
const rename = renameMap.getRenameForPosition(name.getStart());
if (rename) {
return rename.name;
return unescapeVarName(rename.name);
}
}
return name.text;
return unescapeVarName(name.text);
}
}

Expand Down Expand Up @@ -2749,7 +2749,7 @@ ${output}</xml>`;
let userFunction: FunctionDeclaration;

if (ts.isIdentifier(n.expression)) {
userFunction = env.declaredFunctions[n.expression.text];
userFunction = env.declaredFunctions[unescapeVarName(n.expression.text)];
}

if (!asExpression) {
Expand Down Expand Up @@ -3607,6 +3607,13 @@ ${output}</xml>`;
}
}

function unescapeVarName(name: string) {
return name.replace(
/E([0-9a-f]{4,6})X/g,
s => String.fromCodePoint(+`0x${s.slice(1, s.length - 1)}`)
);
}

function isFunctionExpression(node: Node) {
return node.kind === SK.ArrowFunction || node.kind === SK.FunctionExpression;
}
Expand Down
4 changes: 2 additions & 2 deletions pxtlib/commonutil.ts
Expand Up @@ -28,8 +28,8 @@ namespace ts.pxtc.Util {
}

export function htmlEscape(_input: string) {
if (!_input) return _input; // null, undefined, empty string test
return _input.replace(/([^\w .!?\-$])/g, c => "&#" + c.charCodeAt(0) + ";");
if (!_input) return _input;
return _input.replace(/[<>&"'\n]/gu, c => `&#${c.charCodeAt(0)};`);
}

export function htmlUnescape(_input: string) {
Expand Down
2 changes: 1 addition & 1 deletion pxtsim/simdriver.ts
Expand Up @@ -424,7 +424,7 @@ namespace pxsim {
frame.className = 'no-select';

let furl = url || this.getSimUrl().toString();
if (this._runOptions.hideSimButtons) {
if (this._runOptions?.hideSimButtons) {
const urlObject = new URL(furl);
urlObject.searchParams.append("hideSimButtons", "1");
furl = urlObject.toString();
Expand Down
Expand Up @@ -2,7 +2,7 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="x" numlines="1" line0="let x&#58; number&#59;" />
<mutation declaredvars="x" numlines="1" error="Variable declarations must have an initializer" line0="let x: number;" />
</block>
</statement>
</block>
Expand Down
Expand Up @@ -2,10 +2,10 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation numlines="6" error="Unsupported statement in block&#58; ClassDeclaration" line0="class Foo &#123;" line1=" x&#58; number&#59;" line2=" constructor&#40;&#41; &#123;" line3=" this.x &#61; 0" line4=" &#125;" line5="&#125;" />
<mutation numlines="6" error="Unsupported statement in block: ClassDeclaration" line0="class Foo {" line1=" x: number;" line2=" constructor() {" line3=" this.x = 0" line4=" }" line5="}" />
<next>
<block type="typescript_statement">
<mutation declaredvars="y" numlines="1" error="Unsupported syntax kind for output expression block&#58; NewExpression" line0="let y &#61; new Foo&#40;&#41;" />
<mutation declaredvars="y" numlines="1" error="Unsupported syntax kind for output expression block: NewExpression" line0="let y = new Foo()" />
<next>
<block type="device_show_number">
<value name="number">
Expand Down
Expand Up @@ -2,10 +2,10 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="someVar" numlines="1" line0="let someVar &#61; 0 &#38; 9&#59;" />
<mutation declaredvars="someVar" numlines="1" error="Could not find operator &#38;" line0="let someVar = 0 &#38; 9;" />
<next>
<block type="typescript_statement">
<mutation numlines="5" line0="for &#40;&#59;&#59;&#41; &#123;" line1=" let someVar2 &#61; 38&#59;" line2=" someVar2 &#43;&#43;&#59;" line3=" someVar2 &#61; 7 &#94; 6&#59;" line4="&#125;" />
<mutation numlines="5" error="for loops must have an initializer, incrementor, and condition" line0="for (;;) {" line1=" let someVar2 = 38;" line2=" someVar2 ++;" line3=" someVar2 = 7 ^ 6;" line4="}" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -25,7 +25,7 @@
<value name="A">
<shadow type="math_number"><field name="NUM">0</field></shadow>
<block type="typescript_expression">
<field name="EXPRESSION">&#40;x2 &#38; 7&#41;</field>
<field name="EXPRESSION">(x2 &#38; 7)</field>
</block>
</value>
<value name="B">
Expand Down
2 changes: 1 addition & 1 deletion tests/decompile-test/baselines/always_enums.blocks
Expand Up @@ -15,7 +15,7 @@
</value>
<statement name="DO">
<block type="typescript_statement">
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="testNamespace.enumArgument&#40;i&#41;&#59;" />
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="testNamespace.enumArgument(i);" />
</block>
</statement>
</block>
Expand Down
2 changes: 1 addition & 1 deletion tests/decompile-test/baselines/always_enums2.blocks
Expand Up @@ -2,7 +2,7 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="testNamespace.enumArgument&#40;testNamespace.numberArgumentOutput&#40;0&#41;&#41;&#59;" />
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="testNamespace.enumArgument(testNamespace.numberArgumentOutput(0));" />
</block>
</statement>
</block>
Expand Down
2 changes: 1 addition & 1 deletion tests/decompile-test/baselines/always_enums4.blocks
Expand Up @@ -23,7 +23,7 @@
</value>
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="x.testMethodWithEnum&#40;58&#41;" />
<mutation numlines="1" error="Enum arguments may only be literal property access expressions" line0="x.testMethodWithEnum(58)" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -2,7 +2,7 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="a" numlines="1" error="No call info found" line0="let a &#61; pins.A9" />
<mutation declaredvars="a" numlines="1" error="No call info found" line0="let a = pins.A9" />
<next>
<block type="pin_analog_pitch">
<field name="pin">pins.A10</field>
Expand Down
Expand Up @@ -10,19 +10,19 @@
</value>
<next>
<block type="typescript_statement">
<mutation numlines="1" error="left side of for loop conditional must be the variable declared in the initializer" line0="for &#40;let x &#61; 0&#59; y &#60;&#61; 5&#59; x&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="left side of for loop conditional must be the variable declared in the initializer" line0="for (let x = 0; y &#60;= 5; x++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loop conditionals must be binary comparison operations" line0="for &#40;let x2 &#61; 0&#59; false&#59; x2&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop conditionals must be binary comparison operations" line0="for (let x2 = 0; false; x2++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loop conditional operator must be either &#60; or &#60;&#61;" line0="for &#40;let x3 &#61; 0&#59; x3 &#61;&#61; 2&#59; x3&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop conditional operator must be either &#60; or &#60;=" line0="for (let x3 = 0; x3 == 2; x3++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="left side of for loop conditional must be the variable declared in the initializer" line0="for &#40;let x4 &#61; 0&#59; 2 &#60;&#61; 2&#59; x4&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="left side of for loop conditional must be the variable declared in the initializer" line0="for (let x4 = 0; 2 &#60;= 2; x4++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loops must have an initializer&#44; incrementor&#44; and condition" line0="for &#40;let x5 &#61; 0&#59; &#59; x5&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loops must have an initializer, incrementor, and condition" line0="for (let x5 = 0; ; x5++) {}" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -2,10 +2,10 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for &#40;let x &#61; 0&#59; x &#60;&#61; 5&#59; x&#43;&#61; 1&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for (let x = 0; x &#60;= 5; x+= 1) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for &#40;let x2 &#61; 0&#59; x2 &#60;&#61; 5&#59; x2--&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for (let x2 = 0; x2 &#60;= 5; x2--) {}" />
<next>
<block type="variables_set">
<field name="VAR">y</field>
Expand All @@ -16,10 +16,10 @@
</value>
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for &#40;let x3 &#61; 0&#59; x3 &#60;&#61; 5&#59; y&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop incrementors may only increment the variable declared in the initializer" line0="for (let x3 = 0; x3 &#60;= 5; y++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loops must have an initializer&#44; incrementor&#44; and condition" line0="for &#40;let x4 &#61; 0&#59; x4 &#60;&#61; 5&#59;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loops must have an initializer, incrementor, and condition" line0="for (let x4 = 0; x4 &#60;= 5;) {}" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -10,7 +10,7 @@
</value>
<next>
<block type="typescript_statement">
<mutation numlines="1" error="only variable declarations are permitted in for loop initializers" line0="for &#40;1 &#43; 1&#59; x &#60;&#61; 5&#59; x&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="only variable declarations are permitted in for loop initializers" line0="for (1 + 1; x &#60;= 5; x++) {}" />
<next>
<block type="variables_set">
<field name="VAR">x2</field>
Expand All @@ -21,10 +21,10 @@
</value>
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loops must have an initializer&#44; incrementor&#44; and condition" line0="for &#40;&#59; x2 &#60;&#61; 5&#59; x2&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loops must have an initializer, incrementor, and condition" line0="for (; x2 &#60;= 5; x2++) {}" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="for loop with multiple variables not supported" line0="for &#40;let x3 &#61; 0&#44; y &#61; 2&#59; x3 &#60;&#61; 5&#59; x3&#43;&#43;&#41; &#123;&#125;" />
<mutation numlines="1" error="for loop with multiple variables not supported" line0="for (let x3 = 0, y = 2; x3 &#60;= 5; x3++) {}" />
</block>
</next>
</block>
Expand Down
4 changes: 2 additions & 2 deletions tests/decompile-test/baselines/always_image_too_large.blocks
Expand Up @@ -2,10 +2,10 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="item" numlines="7" error="Invalid image pattern &#40;50 expected vs 75 actual&#41;" line0="let item &#61; images.createBigImage&#40;&#96;" line1=" . . . . . . . . . . . . . . ." line2=" . &#35; &#35; &#35; . . &#35; &#35; &#35; . . &#35; &#35; &#35; ." line3=" . &#35; . &#35; . . &#35; . &#35; . . &#35; . &#35; ." line4=" . &#35; &#35; &#35; . . &#35; &#35; &#35; . . &#35; &#35; &#35; ." line5=" . . . . . . . . . . . . . . ." line6=" &#96;&#41;" />
<mutation declaredvars="item" numlines="7" error="Invalid image pattern (50 expected vs 75 actual)" line0="let item = images.createBigImage(`" line1=" . . . . . . . . . . . . . . ." line2=" . # # # . . # # # . . # # # ." line3=" . # . # . . # . # . . # . # ." line4=" . # # # . . # # # . . # # # ." line5=" . . . . . . . . . . . . . . ." line6=" `)" />
<next>
<block type="typescript_statement">
<mutation declaredvars="z" numlines="7" error="Invalid image pattern &#40;50 expected vs 10 actual&#41;" line0="let z &#61; images.createBigImage&#40;&#96;" line1=" . ." line2=" . &#35;" line3=" . &#35;" line4=" . &#35;" line5=" . ." line6=" &#96;&#41;" />
<mutation declaredvars="z" numlines="7" error="Invalid image pattern (50 expected vs 10 actual)" line0="let z = images.createBigImage(`" line1=" . ." line2=" . #" line3=" . #" line4=" . #" line5=" . ." line6=" `)" />
</block>
</next>
</block>
Expand Down
4 changes: 2 additions & 2 deletions tests/decompile-test/baselines/always_local_variable.blocks
Expand Up @@ -2,10 +2,10 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="x" numlines="1" line0="let x &#61; 0" />
<mutation declaredvars="x" numlines="1" line0="let x = 0" />
<next>
<block type="typescript_statement">
<mutation numlines="3" line0="for &#40;&#59;&#59;&#41; &#123;" line1=" x&#43;&#43;&#59;" line2="&#125;" />
<mutation numlines="3" error="for loops must have an initializer, incrementor, and condition" line0="for (;;) {" line1=" x++;" line2="}" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -2,16 +2,16 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation declaredvars="x2" numlines="1" line0="let x2 &#61; 0" />
<mutation declaredvars="x2" numlines="1" line0="let x2 = 0" />
<next>
<block type="typescript_statement">
<mutation declaredvars="x" numlines="1" line0="let x &#61; 0" />
<mutation declaredvars="x" numlines="1" line0="let x = 0" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Unsupported syntax kind for output expression block&#58; NullKeyword" line0="x &#61; null&#59;" />
<mutation numlines="1" error="Unsupported syntax kind for output expression block: NullKeyword" line0="x = null;" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Undefined is not supported in blocks" line0="x2 &#61; undefined&#59;" />
<mutation numlines="1" error="Undefined is not supported in blocks" line0="x2 = undefined;" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -2,16 +2,16 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.defaultArguments&#40;40&#44; 50&#41;&#59;" />
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.defaultArguments(40, 50);" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.multipleDefaultArguments&#40;40&#44; 50&#41;&#59;" />
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.multipleDefaultArguments(40, 50);" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.optionalArgument&#40;40&#44; 50&#41;&#59;" />
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.optionalArgument(40, 50);" />
<next>
<block type="typescript_statement">
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.optionalArgumentWithCallback&#40;&#40;&#41; &#61;&#62; &#123;&#125;&#44; 500&#41;&#59;" />
<mutation numlines="1" error="Function call has more arguments than are supported by its block" line0="testNamespace.optionalArgumentWithCallback(() =&#62; {}, 500);" />
</block>
</next>
</block>
Expand Down
Expand Up @@ -2,9 +2,7 @@
<block type="pxt-on-start">
<statement name="HANDLER">
<block type="typescript_statement">
<mutation numlines="1"
line0="1 &#43; 1"
/>
<mutation numlines="1" error="This expression cannot be assigned to" line0="1 + 1" />
</block>
</statement>
</block>
Expand Down