First step is done.
index.html - playground
This commit is contained in:
parent
b5dd0a9774
commit
b7d220ae12
|
|
@ -853,6 +853,13 @@ var AST_String = DEFNODE("String", "value", {
|
||||||
}
|
}
|
||||||
}, AST_Constant);
|
}, AST_Constant);
|
||||||
|
|
||||||
|
var AST_StringTemplate = DEFNODE("StringTemplate", null, {
|
||||||
|
$documentation: "A string template",
|
||||||
|
$propdoc: {
|
||||||
|
body: "[AST_Statement*] the contents of this string template"
|
||||||
|
}
|
||||||
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Number = DEFNODE("Number", "value", {
|
var AST_Number = DEFNODE("Number", "value", {
|
||||||
$documentation: "A number literal",
|
$documentation: "A number literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
|
|
|
||||||
|
|
@ -13,23 +13,91 @@
|
||||||
<script src="./mozilla-ast.js"></script>
|
<script src="./mozilla-ast.js"></script>
|
||||||
<script src="./translate.js"></script>
|
<script src="./translate.js"></script>
|
||||||
<script src="./std.js"></script>
|
<script src="./std.js"></script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 33.333%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
float: left;
|
||||||
|
font-family: "Andale Mono";
|
||||||
|
}
|
||||||
|
|
||||||
|
#controls {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<textarea id="source" style="width: 100%; min-height: 300px"></textarea>
|
<textarea id="source" onkeyup="compile()"></textarea>
|
||||||
|
<textarea id="translation"></textarea>
|
||||||
|
<textarea id="result"></textarea>
|
||||||
|
<div id="controls"><button id="exec" onclick="exec()">Execute</button></div>
|
||||||
</body>
|
</body>
|
||||||
<script>
|
<script>
|
||||||
var sourceArea = document.getElementById("source"), source;
|
var sourceArea = document.getElementById("source"),
|
||||||
|
translationArea = document.getElementById("translation"),
|
||||||
|
resultArea = document.getElementById("result"),
|
||||||
|
source;
|
||||||
sourceArea.value = source = localStorage.source;
|
sourceArea.value = source = localStorage.source;
|
||||||
|
|
||||||
sourceArea.onkeyup = function(){
|
function compile(){
|
||||||
source = sourceArea.value;
|
source = sourceArea.value;
|
||||||
localStorage.source = source;
|
localStorage.source = source;
|
||||||
};
|
|
||||||
|
stream = OutputStream({ beautify : true });
|
||||||
|
compressor = Compressor();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. compile
|
||||||
|
ast = parse(source);
|
||||||
|
ast = translate(ast);
|
||||||
|
ast.print(stream);
|
||||||
|
translationArea.value = stream.toString();
|
||||||
|
|
||||||
|
// 2. compress
|
||||||
|
ast.figure_out_scope();
|
||||||
|
ast = ast.transform(compressor);
|
||||||
|
|
||||||
|
// 3. mangle
|
||||||
|
ast.figure_out_scope();
|
||||||
|
ast.compute_char_frequency();
|
||||||
|
ast.mangle_names({ sort : true, toplevel : true });
|
||||||
|
|
||||||
|
stream = OutputStream();
|
||||||
|
ast.print(stream);
|
||||||
|
resultArea.value = stream.toString();
|
||||||
|
} catch(e){
|
||||||
|
translationArea.value = '';
|
||||||
|
resultArea.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec(){
|
||||||
|
eval(resultArea.value)
|
||||||
|
}
|
||||||
|
|
||||||
function Translate(){
|
function Translate(){
|
||||||
stream = OutputStream();
|
stream = OutputStream({ beautify : true });
|
||||||
translate(parse(source)).print(stream);
|
translate(parse(source)).print(stream);
|
||||||
return stream.toString();
|
return stream.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compile();
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
153
lib/parse.js
153
lib/parse.js
|
|
@ -227,7 +227,8 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
this.inside = false;
|
this.inside = false;
|
||||||
this.after_at = false;
|
this.after_at = false;
|
||||||
this.inside_at = false;
|
this.inside_at = false;
|
||||||
this.at_balance = 0;
|
this.inside_braces = false;
|
||||||
|
this.balance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
|
|
@ -250,7 +251,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
comments_before : []
|
comments_before : []
|
||||||
};
|
};
|
||||||
|
|
||||||
function peek() { return S.text.charAt(S.pos); };
|
function peek(offset) { return S.text.charAt(S.pos + (offset ? offset : 0)); };
|
||||||
|
|
||||||
function next(signal_eof, in_string) {
|
function next(signal_eof, in_string) {
|
||||||
var ch = S.text.charAt(S.pos++);
|
var ch = S.text.charAt(S.pos++);
|
||||||
|
|
@ -302,14 +303,6 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
nlb : S.newline_before,
|
nlb : S.newline_before,
|
||||||
file : filename
|
file : filename
|
||||||
};
|
};
|
||||||
//if (type == 'string') {
|
|
||||||
//ret.leftoffset = ret.value.match(/[\n\r][ \t]*$/);
|
|
||||||
//ret.value = ret.value.replace(/^[ \t]*[\n\r][ \t]*/,'');
|
|
||||||
//if(offstr[0]){
|
|
||||||
// offstr = offstr[0];
|
|
||||||
// while(ret.value.indexOf(offstr) != -1) ret.value = ret.value.replace(offstr, '\\n');
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
if (!is_comment) {
|
if (!is_comment) {
|
||||||
ret.comments_before = S.comments_before;
|
ret.comments_before = S.comments_before;
|
||||||
S.comments_before = [];
|
S.comments_before = [];
|
||||||
|
|
@ -319,7 +312,6 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
S.newline_before = false;
|
S.newline_before = false;
|
||||||
console.log(ret);
|
|
||||||
return new AST_Token(ret);
|
return new AST_Token(ret);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -394,25 +386,39 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
return num;
|
return num;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_string = with_eof_error("Unterminated string constant", function(){
|
var read_string = with_eof_error("Unterminated string constant", function(raw){
|
||||||
var quote = next(), ret = "";
|
var quote = next(), ret = "";
|
||||||
|
|
||||||
if(S.string.at[S.string.level].inside && S.string.at[S.string.level].inside_at){
|
|
||||||
S.string.level++;
|
|
||||||
S.string.at[S.string.level] = new StringInfo();
|
|
||||||
}
|
|
||||||
S.string.at[S.string.level].inside = true;
|
|
||||||
|
|
||||||
if(quote != '"' && quote != "'" && quote != '`'){
|
if (!raw) {
|
||||||
ret = quote;
|
if (S.string.at[S.string.level].inside && (S.string.at[S.string.level].inside_at || S.string.at[S.string.level].inside_braces)) {
|
||||||
quote = S.string.at[S.string.level].quote;
|
S.string.level++;
|
||||||
} else S.string.at[S.string.level].quote = quote;
|
S.string.at[S.string.level] = new StringInfo();
|
||||||
|
}
|
||||||
|
S.string.at[S.string.level].inside = true;
|
||||||
|
|
||||||
|
if (quote != '"' && quote != "'" && quote != '`') {
|
||||||
|
ret = quote;
|
||||||
|
quote = S.string.at[S.string.level].quote;
|
||||||
|
} else
|
||||||
|
|
||||||
if (peek() == '@') return token("string", "");
|
if (quote == S.string.at[S.string.level].quote){
|
||||||
|
S.string.at[S.string.level].inside = false;
|
||||||
|
S.string.at[S.string.level].quote = '';
|
||||||
|
if(S.string.level != 0){
|
||||||
|
delete S.string.at[S.string.level];
|
||||||
|
S.string.level--;
|
||||||
|
}
|
||||||
|
return next_token();
|
||||||
|
} else
|
||||||
|
|
||||||
|
S.string.at[S.string.level].quote = quote;
|
||||||
|
|
||||||
|
if (peek() == '@' || peek() == '{' && peek(1) == '{') return token("string", "");
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true);
|
var ch = next(true);
|
||||||
if (ch == "\\") {
|
if (!raw && ch == "\\") {
|
||||||
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
||||||
// https://github.com/mishoo/UglifyJS/issues/178
|
// https://github.com/mishoo/UglifyJS/issues/178
|
||||||
var octal_len = 0, first = null;
|
var octal_len = 0, first = null;
|
||||||
|
|
@ -431,16 +437,18 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
else ch = read_escaped_char(true);
|
else ch = read_escaped_char(true);
|
||||||
}
|
}
|
||||||
else if (ch == quote) {
|
else if (ch == quote) {
|
||||||
S.string.at[S.string.level].inside = false;
|
if(!raw){
|
||||||
S.string.at[S.string.level].quote = '';
|
S.string.at[S.string.level].inside = false;
|
||||||
if(S.string.level != 0){
|
S.string.at[S.string.level].quote = '';
|
||||||
delete S.string.at[S.string.level];
|
if(S.string.level != 0){
|
||||||
S.string.level--;
|
delete S.string.at[S.string.level];
|
||||||
|
S.string.level--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret += ch;
|
ret += ch;
|
||||||
if (peek() == '@') break;
|
if (!raw && (peek() == '@' || peek() == '{' && peek(1) == '{')) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return token("string", ret);
|
return token("string", ret);
|
||||||
|
|
@ -456,12 +464,19 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
|
|
||||||
if (S.string.at[S.string.level].inside && peek() == '{') {
|
if (S.string.at[S.string.level].inside && peek() == '{') {
|
||||||
S.string.at[S.string.level].inside_at = true;
|
S.string.at[S.string.level].inside_at = true;
|
||||||
S.string.at[S.string.level].at_balance = 1;
|
S.string.at[S.string.level].balance = 1;
|
||||||
return token("punc", "@" + next());
|
return token("punc", "@" + next());
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_error('Unexpected character "@"');
|
parse_error('Unexpected character "@"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function read_braces(){
|
||||||
|
next(), next();
|
||||||
|
S.string.at[S.string.level].inside_braces = true;
|
||||||
|
S.string.at[S.string.level].balance = 1;
|
||||||
|
return token("punc", "{{");
|
||||||
|
}
|
||||||
|
|
||||||
function skip_line_comment(type) {
|
function skip_line_comment(type) {
|
||||||
var regex_allowed = S.regex_allowed;
|
var regex_allowed = S.regex_allowed;
|
||||||
|
|
@ -601,14 +616,13 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
return read_regexp(force_regexp);
|
return read_regexp(force_regexp);
|
||||||
|
|
||||||
var ch;
|
var ch;
|
||||||
|
if (S.string.at[S.string.level].inside && !S.string.at[S.string.level].after_at && !S.string.at[S.string.level].inside_at && !S.string.at[S.string.level].inside_braces) {
|
||||||
if (S.string.at[S.string.level].inside && !S.string.at[S.string.level].after_at && !S.string.at[S.string.level].inside_at) {
|
|
||||||
start_token();
|
|
||||||
ch = peek();
|
ch = peek();
|
||||||
if (ch == '@') return read_at();
|
if (ch == '@') return read_at();
|
||||||
|
if (ch == '{' && peek(1) == '{') return read_braces();
|
||||||
return read_string();
|
return read_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_whitespace();
|
skip_whitespace();
|
||||||
start_token();
|
start_token();
|
||||||
if (html5_comments) {
|
if (html5_comments) {
|
||||||
|
|
@ -631,17 +645,23 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
}
|
}
|
||||||
if (is_digit(code)) return read_num();
|
if (is_digit(code)) return read_num();
|
||||||
if (PUNC_CHARS(ch)){
|
if (PUNC_CHARS(ch)){
|
||||||
if (S.string.at[S.string.level].inside && S.string.at[S.string.level].inside_at) {
|
if (S.string.at[S.string.level].inside && (S.string.at[S.string.level].inside_at || S.string.at[S.string.level].inside_braces)) {
|
||||||
if (ch == '{') S.string.at[S.string.level].at_balance++;
|
if (ch == '{') S.string.at[S.string.level].balance++;
|
||||||
else if (ch == '}') S.string.at[S.string.level].at_balance--;
|
else if (ch == '}') S.string.at[S.string.level].balance--;
|
||||||
|
|
||||||
if (S.string.at[S.string.level].at_balance == 0) S.string.at[S.string.level].inside_at = false;
|
if (S.string.at[S.string.level].balance == 0)
|
||||||
|
if (S.string.at[S.string.level].inside_at) S.string.at[S.string.level].inside_at = false;
|
||||||
|
else {
|
||||||
|
S.string.at[S.string.level].inside_braces = false;
|
||||||
|
return next(), next(), token("punc", "}}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return token("punc", next());
|
return token("punc", next());
|
||||||
}
|
}
|
||||||
if (ch == '@') return read_at();
|
if (ch == '@') return read_at();
|
||||||
if (OPERATOR_CHARS(ch)) return read_operator();
|
if (OPERATOR_CHARS(ch)) return read_operator();
|
||||||
|
if (ch == 'r' && (peek(1) == '"' || peek(1) == "'" || peek(1) == '`')) return next(), read_string(true);
|
||||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||||
parse_error("Unexpected character '" + ch + "'");
|
parse_error("Unexpected character '" + ch + "'");
|
||||||
};
|
};
|
||||||
|
|
@ -1200,6 +1220,57 @@ function parse($TEXT, options) {
|
||||||
}), true);
|
}), true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function string_template_(start_token) {
|
||||||
|
var body = [new AST_String({ start: start_token, end: start_token, value: start_token.value })];
|
||||||
|
next();
|
||||||
|
|
||||||
|
//if (!is('punc', '@') && !is('punc', '@{')) return body[0];
|
||||||
|
while (is('punc', '@') || is('punc', '@{') || is('punc', '{{') || is('string', null))
|
||||||
|
if (is('string', null)) {
|
||||||
|
body.push(new AST_String({ start: S.token, end: S.token, value: S.token.value }));
|
||||||
|
next();
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (is('punc', '@')) {
|
||||||
|
next();
|
||||||
|
body.push(_make_symbol(AST_SymbolRef));
|
||||||
|
next();
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (is('punc', '@{')) {
|
||||||
|
next();
|
||||||
|
body.push(expression(true));
|
||||||
|
expect('}');
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (is('punc', '{{')) {
|
||||||
|
next();
|
||||||
|
body.push(expression(true));
|
||||||
|
expect('}}');
|
||||||
|
}
|
||||||
|
|
||||||
|
var last = body[body.length - 1];
|
||||||
|
body[0].value = body[0].value.replace(/^[ \t]*[\n\r]/,'');
|
||||||
|
if (last instanceof AST_String) {
|
||||||
|
var offstr = last.value.match(/[\n\r][ \t]*$/);
|
||||||
|
if(offstr){
|
||||||
|
offstr = offstr[0];
|
||||||
|
for(var i in body) if(body[i] instanceof AST_String){
|
||||||
|
body[i].value = body[i].value.replace(new RegExp(offstr, 'g'), '\n');
|
||||||
|
body[i].value = body[i].value.replace(/\n/g, '\n');
|
||||||
|
}
|
||||||
|
last.value = last.value.replace(/[\n\r]$/,'');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.length == 1) return body[0];
|
||||||
|
return new AST_StringTemplate({
|
||||||
|
start : start_token,
|
||||||
|
end : prev(),
|
||||||
|
body : body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function as_atom_node() {
|
function as_atom_node() {
|
||||||
var tok = S.token, ret;
|
var tok = S.token, ret;
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
|
|
@ -1211,8 +1282,8 @@ function parse($TEXT, options) {
|
||||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||||
break;
|
break;
|
||||||
case "string":
|
case "string":
|
||||||
ret = new AST_String({ start: tok, end: tok, value: tok.value });
|
return string_template_(tok);//new AST_String({ start: tok, end: tok, value: tok.value });
|
||||||
break;
|
//break;
|
||||||
case "regexp":
|
case "regexp":
|
||||||
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -92,22 +92,19 @@ function translate(tree){
|
||||||
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
|
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
|
||||||
};
|
};
|
||||||
props.expression = new AST_SymbolRef({
|
props.expression = new AST_SymbolRef({
|
||||||
name : '$_cola_isntset',
|
name : '$_cola_isntset',
|
||||||
start : props.start,
|
start : props.start,
|
||||||
end : props.start
|
end : props.start
|
||||||
});
|
});
|
||||||
|
|
||||||
parent = CopyObject(parent);
|
|
||||||
parent.body = CopyObject(node);
|
|
||||||
|
|
||||||
newNode = new AST_If({
|
newNode = new AST_If({
|
||||||
body : parent,
|
body : CopyObject(parent),
|
||||||
start : new AST_Token({ nlb : false, type : 'keyword', value : 'if' }),
|
start : new AST_Token({ nlb : false, type : 'keyword', value : 'if' }),
|
||||||
end : new AST_Token({ nlb : false, type : 'punc', value : ';' }),
|
end : new AST_Token({ nlb : false, type : 'punc', value : ';' }),
|
||||||
condition : new AST_Call(props)
|
condition : new AST_Call(props)
|
||||||
});
|
});
|
||||||
queue.push(function(){
|
queue.push(function(){
|
||||||
ReplaceObject(node, newNode);
|
ReplaceObject(parent, newNode);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
node.operator = '=';
|
node.operator = '=';
|
||||||
|
|
@ -118,9 +115,9 @@ function translate(tree){
|
||||||
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
|
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
|
||||||
};
|
};
|
||||||
props.expression = new AST_SymbolRef({
|
props.expression = new AST_SymbolRef({
|
||||||
name : '$_cola_isntset',
|
name : '$_cola_isntset',
|
||||||
start : props.start,
|
start : props.start,
|
||||||
end : props.start
|
end : props.start
|
||||||
});
|
});
|
||||||
|
|
||||||
newNode = new AST_Conditional({
|
newNode = new AST_Conditional({
|
||||||
|
|
@ -173,6 +170,28 @@ function translate(tree){
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
|
|
||||||
|
if(node instanceof AST_StringTemplate){
|
||||||
|
newNode = new AST_Binary({
|
||||||
|
operator : '+',
|
||||||
|
left : node.body[0],
|
||||||
|
right : node.body[1],
|
||||||
|
start : node.body[0].start,
|
||||||
|
end : node.body[1].end
|
||||||
|
});
|
||||||
|
for(var i = 2; i < node.body.length; i++)
|
||||||
|
newNode = new AST_Binary({
|
||||||
|
operator : '+',
|
||||||
|
left : newNode,
|
||||||
|
right : node.body[i],
|
||||||
|
start : newNode.start,
|
||||||
|
end : node.body[i].end
|
||||||
|
});
|
||||||
|
|
||||||
|
queue.push(function(){
|
||||||
|
ReplaceObject(node, newNode);
|
||||||
|
});
|
||||||
|
} else
|
||||||
|
|
||||||
if(node instanceof AST_RegExp && (node.value.indexOf('\n') != -1 || /\/[\w]*x[\w]*$/.test(node.value))){
|
if(node instanceof AST_RegExp && (node.value.indexOf('\n') != -1 || /\/[\w]*x[\w]*$/.test(node.value))){
|
||||||
node.value = node.value.replace(/[\r\n\s]/g,'').replace(/(\/[\w]*)x([\w]*$)/, '$1$2');
|
node.value = node.value.replace(/[\r\n\s]/g,'').replace(/(\/[\w]*)x([\w]*$)/, '$1$2');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user