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);
|
||||
|
||||
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: {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
153
lib/parse.js
153
lib/parse.js
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user