First step is done.

index.html - playground
This commit is contained in:
Onoshko Dan 2014-04-15 17:52:01 +07:00
parent b5dd0a9774
commit b7d220ae12
4 changed files with 220 additions and 55 deletions

View File

@ -853,6 +853,13 @@ var AST_String = DEFNODE("String", "value", {
}
}, 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", {
$documentation: "A number literal",
$propdoc: {

View File

@ -13,23 +13,91 @@
<script src="./mozilla-ast.js"></script>
<script src="./translate.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>
<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>
<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.onkeyup = function(){
function compile(){
source = sourceArea.value;
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(){
stream = OutputStream();
stream = OutputStream({ beautify : true });
translate(parse(source)).print(stream);
return stream.toString();
}
compile();
</script>
</html>

View File

@ -227,7 +227,8 @@ function tokenizer($TEXT, filename, html5_comments) {
this.inside = false;
this.after_at = false;
this.inside_at = false;
this.at_balance = 0;
this.inside_braces = false;
this.balance = 0;
}
var S = {
@ -250,7 +251,7 @@ function tokenizer($TEXT, filename, html5_comments) {
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) {
var ch = S.text.charAt(S.pos++);
@ -302,14 +303,6 @@ function tokenizer($TEXT, filename, html5_comments) {
nlb : S.newline_before,
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) {
ret.comments_before = S.comments_before;
S.comments_before = [];
@ -319,7 +312,6 @@ function tokenizer($TEXT, filename, html5_comments) {
}
}
S.newline_before = false;
console.log(ret);
return new AST_Token(ret);
};
@ -394,25 +386,39 @@ function tokenizer($TEXT, filename, html5_comments) {
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 = "";
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 != '`'){
ret = quote;
quote = S.string.at[S.string.level].quote;
} else S.string.at[S.string.level].quote = quote;
if (!raw) {
if (S.string.at[S.string.level].inside && (S.string.at[S.string.level].inside_at || S.string.at[S.string.level].inside_braces)) {
S.string.level++;
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 (;;) {
var ch = next(true);
if (ch == "\\") {
if (!raw && ch == "\\") {
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
// https://github.com/mishoo/UglifyJS/issues/178
var octal_len = 0, first = null;
@ -431,16 +437,18 @@ function tokenizer($TEXT, filename, html5_comments) {
else ch = read_escaped_char(true);
}
else if (ch == 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--;
if(!raw){
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--;
}
}
break;
}
ret += ch;
if (peek() == '@') break;
if (!raw && (peek() == '@' || peek() == '{' && peek(1) == '{')) break;
}
return token("string", ret);
@ -456,12 +464,19 @@ function tokenizer($TEXT, filename, html5_comments) {
if (S.string.at[S.string.level].inside && peek() == '{') {
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());
}
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) {
var regex_allowed = S.regex_allowed;
@ -601,14 +616,13 @@ function tokenizer($TEXT, filename, html5_comments) {
return read_regexp(force_regexp);
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) {
start_token();
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) {
ch = peek();
if (ch == '@') return read_at();
if (ch == '{' && peek(1) == '{') return read_braces();
return read_string();
}
skip_whitespace();
start_token();
if (html5_comments) {
@ -631,17 +645,23 @@ function tokenizer($TEXT, filename, html5_comments) {
}
if (is_digit(code)) return read_num();
if (PUNC_CHARS(ch)){
if (S.string.at[S.string.level].inside && S.string.at[S.string.level].inside_at) {
if (ch == '{') S.string.at[S.string.level].at_balance++;
else if (ch == '}') S.string.at[S.string.level].at_balance--;
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].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());
}
if (ch == '@') return read_at();
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();
parse_error("Unexpected character '" + ch + "'");
};
@ -1200,6 +1220,57 @@ function parse($TEXT, options) {
}), 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() {
var tok = S.token, ret;
switch (tok.type) {
@ -1211,8 +1282,8 @@ function parse($TEXT, options) {
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
break;
case "string":
ret = new AST_String({ start: tok, end: tok, value: tok.value });
break;
return string_template_(tok);//new AST_String({ start: tok, end: tok, value: tok.value });
//break;
case "regexp":
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
break;

View File

@ -92,22 +92,19 @@ function translate(tree){
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
};
props.expression = new AST_SymbolRef({
name : '$_cola_isntset',
name : '$_cola_isntset',
start : props.start,
end : props.start
end : props.start
});
parent = CopyObject(parent);
parent.body = CopyObject(node);
newNode = new AST_If({
body : parent,
body : CopyObject(parent),
start : new AST_Token({ nlb : false, type : 'keyword', value : 'if' }),
end : new AST_Token({ nlb : false, type : 'punc', value : ';' }),
condition : new AST_Call(props)
});
queue.push(function(){
ReplaceObject(node, newNode);
ReplaceObject(parent, newNode);
});
} else {
node.operator = '=';
@ -118,9 +115,9 @@ function translate(tree){
end : new AST_Token({ nlb : false, type : 'punc', value : ')' })
};
props.expression = new AST_SymbolRef({
name : '$_cola_isntset',
name : '$_cola_isntset',
start : props.start,
end : props.start
end : props.start
});
newNode = new AST_Conditional({
@ -173,6 +170,28 @@ function translate(tree){
});
} 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))){
node.value = node.value.replace(/[\r\n\s]/g,'').replace(/(\/[\w]*)x([\w]*$)/, '$1$2');
}