Merge branch 'master' of github.com:Microsoft/TouchDevelop

This commit is contained in:
Michal Moskal 2015-04-06 13:07:51 -07:00
Родитель 4c695a0dae bdf104434a
Коммит 3d339de436
11 изменённых файлов: 197 добавлений и 62 удалений

Просмотреть файл

@ -35,6 +35,7 @@ module TDev {
export var isWindows8plus = false;
export var isCompiledApp = false;
export var isWP8app = false;
export var isHosted = false;
export var browser = BrowserSoftware.unknown;
export var browserVersion = 0;
export var browserVersion2 = 0; // not set for pinned iOS apps; look at webkitVersion instead
@ -113,6 +114,11 @@ module TDev {
export function detect() {
startTimestamp = new Date().getTime(); // no Util here
if ((<any>window).touchDevelopExec || (<any>window).mcefQuery) {
isHosted = true;
Browser.screenshots = true;
}
if ((<any>window).isNodeJS) {
isNodeJS = true
isHeadless = true

Просмотреть файл

@ -191,9 +191,7 @@ module TDev
public additionalFullScreenButtons(): HTMLElement[] {
var btns = [];
if (ScriptEditorWorldInfo.status == "published")
btns.push(
HTML.mkRoundButton("svg:camera,black", lf("screenshot"), Ticks.wallScreenshot, () => this.takeScreenshot())
);
btns.push(HTML.mkRoundButton("svg:camera,black", lf("screenshot"), Ticks.wallScreenshot, () => this.takeScreenshot()));
return btns;
}

Просмотреть файл

@ -214,7 +214,11 @@ module TDev {
case MessageType.Upgrade:
var message2 = <Message_Upgrade> event.data;
var text = AST.Json.serialize(message2.ast);
console.log(text);
Browser.TheHost.openNewScriptAsync({
editorName: "touchdevelop",
scriptName: message2.name,
scriptText: text
});
break;
default:

Просмотреть файл

@ -213,7 +213,7 @@ module TDev.Browser {
}
export function hubTheme(): HubTheme {
var key = localStorage.getItem("hubTheme");
var key = localStorage.getItem("hubTheme");
return key ? Browser.hubThemes[key] : undefined;
}

Просмотреть файл

@ -64,6 +64,7 @@ module TDev {
export interface Message_Upgrade extends Message {
type: MessageType; // == MessageType.Message_Upgrade
name: string;
ast: any // AST.Json.JApp
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -300,7 +300,7 @@ module TDev.RT {
//? Indicates if the `app->host_exec` action can be used to run host commands.
//@ betaOnly
public has_host(): boolean {
return !!(<any>window).mcefQuery || !!(<any>window).touchDevelopExec;
return Browser.isHosted;
}
//? Where are we running from: "editor", "website", "nodejs", "mobileapp", "plugin"
@ -713,39 +713,44 @@ module TDev.RT {
return r
}
export function hostExecAsync(message: string): Promise {
return new Promise((onSuccess, onError, onProgress) => {
var mcefQuery = (<any>window).mcefQuery;
if (mcefQuery) {
mcefQuery({
request: message,
persistent: false,
onSuccess: function (response) {
onSuccess(response);
},
onFailure: function (error_code, error_message) {
onSuccess(JSON.stringify({ error: error_code, message: error_message }));
}
});
return;
}
var exec = (<any>window).touchDevelopExec;
if (!exec) {
App.log("window.touchDevelopExec function not defined");
onSuccess(undefined);
return;
}
try {
exec(message,(result) => { onSuccess(result); });
}
catch (e) {
App.logEvent(App.DEBUG, "app", "touchDevelopExec failed", undefined);
onSuccess(undefined);
}
});
}
//? Invokes the host to execute a command described in the message and returns the response. There is no restriction on the format of the request and response. If not available or errored, returns invalid.
//@ async readsMutable returns(string) betaOnly
export function host_exec(message: string, r: ResumeCtx) {
var mcefQuery = (<any>window).mcefQuery;
if (mcefQuery) {
mcefQuery({
request: message,
persistent: false,
onSuccess: function (response) {
r.resumeVal(response);
},
onFailure: function (error_code, error_message) {
r.resumeVal(JSON.stringify({ error: error_code, message: error_message }));
}
});
return;
}
var exec = (<any>window).touchDevelopExec;
if (!exec) {
App.log("window.touchDevelopExec function not defined");
r.resumeVal(undefined);
return;
}
try {
exec(message, (result) => { r.resumeVal(result); });
}
catch (e) {
App.logEvent(App.DEBUG, "app", "touchDevelopExec failed", undefined);
r.resumeVal(undefined);
}
return hostExecAsync(message).done(resp => r.resumeVal(resp));
}
}
}

Просмотреть файл

@ -470,6 +470,19 @@ module TDev.RT {
export module ScreenshotManager {
export var toScreenshotURLAsync = (rt: RuntimeHost): Promise => { // string {
// TODO: move somewhere else
if (App.env().has_host()) {
var durl: string;
return App.hostExecAsync("screen.min")
.then(() => new Promise((onSuccess, onError, onProcess) => {
Util.setTimeout(100,() => onSuccess(undefined));
})).then(() => App.hostExecAsync("screen.screenshot"))
.then((url) => {
durl = url;
return App.hostExecAsync("screen.show");
}).then(() => durl);
}
var c = rt.toScreenshotCanvas();
try {
var data = c ? c.toDataURL('image/png') : undefined;

Просмотреть файл

@ -328,6 +328,7 @@ module TDev {
name: getName(),
description: getDescription()
}),
name: getName()+" (converted)",
});
});
$("#command-run").addEventListener("click", () => {

2
www/blockly/blockly.d.ts поставляемый
Просмотреть файл

@ -18,7 +18,7 @@ declare module Blockly {
}
class ControlsIfBlock extends Block {
elseIfCount_: number;
elseifCount_: number;
elseCount_: number;
}

Просмотреть файл

@ -10,25 +10,47 @@ import B = Blockly;
// A series of utility functions for constructing various J* AST nodes.
module Helpers {
function assert(x: boolean) {
if (!x)
throw "Assertion failure";
}
// Digits are operators...
export function mkDigit(x: string): J.JOperator {
return mkOp(x);
}
export function mkStringLiteral(x: string): J.JStringLiteral {
return {
nodeType: "stringLiteral",
id: null,
value: x
};
}
export function mkOp(x: string): J.JOperator {
return {
nodeType: "operator",
id: "TODO",
id: null,
op: x
};
}
export function mkPropertyRef(x: string): J.JPropertyRef {
return {
nodeType: "propertyRef",
id: null,
name: x,
parent: null,
};
}
// Generates a local definition for [x] at type [t]; this is not enough to
// properly define a variable, though (see [mkDefAndAssign]).
export function mkDef(x: string, t: string): J.JLocalDef {
return {
nodeType: "localDef",
id: "TODO",
id: null,
name: x,
type: <any> t, // the interface is a lie
};
@ -38,7 +60,7 @@ module Helpers {
export function mkLocalRef(x: string): J.JLocalRef {
return {
nodeType: "localRef",
id: "TODO",
id: null,
name: x,
localId: null // same here
}
@ -52,7 +74,7 @@ module Helpers {
export function mkExprHolder(defs: J.JLocalDef[], toks: J.JToken[]): J.JExprHolder {
return {
nodeType: "exprHolder",
id: "TODO",
id: null,
tokens: toks,
tree: null,
locals: defs,
@ -63,7 +85,7 @@ module Helpers {
export function mkExprStmt(expr: J.JExpr): J.JStmt {
return {
nodeType: "exprStmt",
id: "TODO",
id: null,
expr: expr,
};
}
@ -71,12 +93,45 @@ module Helpers {
export function mkWhile(condition: J.JToken[], body: J.JStmt[]): J.JStmt {
return {
nodeType: "while",
id: "TODO",
id: null,
condition: mkExprHolder([], condition),
body: body
};
}
export function mkSimpleIf(condition: J.JToken[], thenBranch: J.JStmt[]): J.JIf {
return {
nodeType: "if",
id: null,
condition: mkExprHolder([], condition),
thenBody: thenBranch,
elseBody: null,
isElseIf: false,
};
}
// This function takes care of generating an if node *and* de-constructing the
// else branch to abide by the TouchDevelop representation (see comments in
// [jsonInterfaces.ts]).
export function mkIf(condition: J.JToken[], thenBranch: J.JStmt[], elseBranch: J.JStmt[]): J.JIf[] {
var ifNode = mkSimpleIf(condition, thenBranch)
// The transformation into a "flat" if / else if / else sequence is only
// valid if the else branch it itself such a sequence.
var fitForFlattening = elseBranch.length && elseBranch.every((s: J.JStmt, i: number) =>
s.nodeType == "if" && (i == 0 || (<J.JIf> s).isElseIf)
);
if (fitForFlattening) {
var first = <J.JIf> elseBranch[0];
assert(!first.isElseIf);
first.isElseIf = true;
return [ifNode].concat(<J.JIf[]> elseBranch);
} else {
ifNode.elseBody = elseBranch;
return [ifNode];
}
}
// Generate the AST for:
// [var x: t := e]
export function mkDefAndAssign(x: string, t: string, e: J.JToken[]): J.JStmt {
@ -92,7 +147,7 @@ module Helpers {
export function mkAction(name: string, body: J.JStmt[]): J.JAction {
return {
nodeType: "action",
id: "TODO",
id: null,
name: name,
body: body,
inParameters: [],
@ -106,10 +161,10 @@ module Helpers {
};
}
export function mkApp(name: string, description: string, actions: J.JAction[]) {
export function mkApp(name: string, description: string, actions: J.JAction[]): J.JApp {
return {
nodeType: "app",
id: "TODO",
id: null,
textVersion: "v2.2,js,ctx,refs,localcloud,unicodemodel,allasync,upperplex",
jsonVersion: "v0.1,resolved",
@ -148,29 +203,44 @@ interface Expr {
prec: number;
}
function compileNumber(b: B.Block): J.JOperator[] {
function compileNumber(b: B.Block): Expr {
var n = b.getFieldValue("NUM")+"";
var toks: J.JOperator[] = [];
for (var i = 0; i < n.length; ++i)
toks.push(Helpers.mkOp(n[i]));
return toks;
return {
tokens: toks,
prec: 0
};
}
// 0 is for atomic tokens
var precedenceTable: { [index: string]: number } = {
"*": 1,
"/": 1,
"+": 2,
"-": 2,
"<": 3,
"<=": 3,
">": 3,
">=": 3,
"=": 4,
"!=": 4,
};
// Convert a blockly "OP" field into a TouchDevelop operator.
// TODO: unary minus, power
var opToTok: { [index: string]: string } = {
"ADD": "+",
"MINUS": "-",
"MULTIPLY": "*",
"DIVIDE": "/",
"POWER": "",
//"POWER": "", // TODO
"EQ": "=",
"NEQ": "!=",
"LT": "<",
"LTE": "<=",
"GT": ">",
"GTE": ">=",
};
function wrapParentheses(e: J.JToken[]): J.JToken[] {
@ -179,8 +249,6 @@ function wrapParentheses(e: J.JToken[]): J.JToken[] {
function compileArithmetic(b: B.Block): Expr {
var bOp = b.getFieldValue("OP");
if (bOp == "POWER")
throw "TODO";
var prec = precedenceTable[opToTok[bOp]];
var op = Helpers.mkOp(opToTok[bOp]);
var left = compileExpression(b.getInputTargetBlock("A"));
@ -194,15 +262,31 @@ function compileArithmetic(b: B.Block): Expr {
};
}
function compileVariableGet(b: B.Block): Expr {
return {
tokens: [Helpers.mkLocalRef(b.getFieldValue("VAR"))],
prec: 0
};
}
function compileText(b: B.Block): Expr {
return {
tokens: [Helpers.mkStringLiteral(b.getFieldValue("TEXT"))],
prec: 0
};
}
function compileExpression(b: B.Block): Expr {
switch (b.type) {
case "math_number":
return {
tokens: compileNumber(b),
prec: 0
};
return compileNumber(b);
case "math_arithmetic":
case "logic_compare":
return compileArithmetic(b);
case "variables_get":
return compileVariableGet(b);
case "text":
return compileText(b);
}
throw (b.type + " is not an expression block or is not supported");
// unreachable
@ -213,8 +297,19 @@ function compileExpression(b: B.Block): Expr {
// Statements
///////////////////////////////////////////////////////////////////////////////
function compileControlsIf(b: B.ControlsIfBlock): J.JStmt {
throw "Not implemented";
function compileControlsIf(b: B.ControlsIfBlock): J.JStmt[] {
var stmts: J.JIf[] = [];
for (var i = 0; i <= b.elseifCount_; ++i) {
var cond = compileExpression(b.getInputTargetBlock("IF"+i)).tokens;
var thenBranch = compileStatements(b.getInputTargetBlock("DO"+i));
stmts.push(Helpers.mkSimpleIf(cond, thenBranch));
if (i > 0)
stmts[stmts.length - 1].isElseIf = true;
}
if (b.elseCount_) {
stmts[stmts.length - 1].elseBody = compileStatements(b.getInputTargetBlock("ELSE"));
}
return stmts;
}
function compileControlsFor(b: B.Block): J.JStmt[] {
@ -249,18 +344,30 @@ function compileControlsFor(b: B.Block): J.JStmt[] {
];
}
function compilePrint(b: B.Block): J.JStmt {
var text = compileExpression(b.getInputTargetBlock("TEXT")).tokens;
var tokens = text.concat([
Helpers.mkPropertyRef("post to wall"),
]);
return Helpers.mkExprStmt(Helpers.mkExprHolder([], tokens));
}
function compileStatements(b: B.Block): J.JStmt[] {
var stmts: J.JStmt[] = [];
while (b) {
switch (b.type) {
case 'controls_if':
// stmts.push(compileControlsIf(<B.ControlsIfBlock> b));
stmts = stmts.concat(compileControlsIf(<B.ControlsIfBlock> b));
break;
case 'controls_for':
stmts = stmts.concat(compileControlsFor(b));
break;
case 'text_print':
stmts.push(compilePrint(b));
break;
default:
throw (b.type + " is not a statement block or is not supported");
}