style-script 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/bin/style +5 -0
- data/examples/blocks.style +57 -0
- data/examples/code.style +173 -0
- data/examples/hello.style +1 -0
- data/examples/poignant.style +186 -0
- data/examples/potion.style +205 -0
- data/examples/underscore.style +603 -0
- data/lib/style-script.rb +21 -0
- data/lib/style_script/command_line.rb +235 -0
- data/lib/style_script/grammar.y +491 -0
- data/lib/style_script/lexer.js +363 -0
- data/lib/style_script/lexer.rb +272 -0
- data/lib/style_script/nodes.js +756 -0
- data/lib/style_script/nodes.rb +1079 -0
- data/lib/style_script/parse_error.rb +29 -0
- data/lib/style_script/parser.js +544 -0
- data/lib/style_script/parser.rb +2716 -0
- data/lib/style_script/repl.js +33 -0
- data/lib/style_script/rewriter.js +377 -0
- data/lib/style_script/rewriter.rb +289 -0
- data/lib/style_script/runner.js +11 -0
- data/lib/style_script/scope.js +129 -0
- data/lib/style_script/scope.rb +95 -0
- data/lib/style_script/std/style-script.js +96 -0
- data/lib/style_script/style-script.js +50 -0
- data/lib/style_script/value.rb +64 -0
- data/package.json +8 -0
- data/style-script.gemspec +21 -0
- metadata +93 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
(function(){
|
2
|
+
var style, paths;
|
3
|
+
// Quickie script to compile and run all the files given as arguments.
|
4
|
+
process.mixin(require('sys'));
|
5
|
+
style = require('./style-script');
|
6
|
+
paths = process.ARGV;
|
7
|
+
paths = paths.slice(2, paths.length);
|
8
|
+
paths.length ? style.compile_files(paths, function(js) {
|
9
|
+
return eval(js);
|
10
|
+
}) : require('./repl');
|
11
|
+
})();
|
@@ -0,0 +1,129 @@
|
|
1
|
+
(function(){
|
2
|
+
var Scope, succ;
|
3
|
+
var __hasProp = Object.prototype.hasOwnProperty;
|
4
|
+
// Scope objects form a tree corresponding to the shape of the function
|
5
|
+
// definitions present in the script. They provide lexical scope, to determine
|
6
|
+
// whether a variable has been seen before or if it needs to be declared.
|
7
|
+
//
|
8
|
+
// Initialize a scope with its parent, for lookups up the chain,
|
9
|
+
// as well as the Expressions body where it should declare its variables,
|
10
|
+
// and the function that it wraps.
|
11
|
+
Scope = (exports.Scope = function Scope(parent, expressions, method) {
|
12
|
+
var __a;
|
13
|
+
this.parent = parent;
|
14
|
+
this.expressions = expressions;
|
15
|
+
this.method = method;
|
16
|
+
this.variables = {
|
17
|
+
};
|
18
|
+
this.temp_variable = this.parent ? this.parent.temp_variable : '__a';
|
19
|
+
__a = this;
|
20
|
+
return Scope === this.constructor ? this : __a;
|
21
|
+
});
|
22
|
+
// Look up a variable in lexical scope, or declare it if not found.
|
23
|
+
Scope.prototype.find = function find(name, remote) {
|
24
|
+
var found;
|
25
|
+
found = this.check(name);
|
26
|
+
if (found || remote) {
|
27
|
+
return found;
|
28
|
+
}
|
29
|
+
this.variables[name] = 'var';
|
30
|
+
return found;
|
31
|
+
};
|
32
|
+
// Define a local variable as originating from a parameter in current scope
|
33
|
+
// -- no var required.
|
34
|
+
Scope.prototype.parameter = function parameter(name) {
|
35
|
+
return this.variables[name] = 'param';
|
36
|
+
};
|
37
|
+
// Just check to see if a variable has already been declared.
|
38
|
+
Scope.prototype.check = function check(name) {
|
39
|
+
if (this.variables[name]) {
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
return !!(this.parent && this.parent.check(name));
|
43
|
+
};
|
44
|
+
// You can reset a found variable on the immediate scope.
|
45
|
+
Scope.prototype.reset = function reset(name) {
|
46
|
+
return delete this.variables[name];
|
47
|
+
};
|
48
|
+
// Find an available, short, name for a compiler-generated variable.
|
49
|
+
Scope.prototype.free_variable = function free_variable() {
|
50
|
+
while (this.check(this.temp_variable)) {
|
51
|
+
((this.temp_variable = succ(this.temp_variable)));
|
52
|
+
}
|
53
|
+
this.variables[this.temp_variable] = 'var';
|
54
|
+
return this.temp_variable;
|
55
|
+
};
|
56
|
+
// Ensure that an assignment is made at the top of scope (or top-level
|
57
|
+
// scope, if requested).
|
58
|
+
Scope.prototype.assign = function assign(name, value, top_level) {
|
59
|
+
if (top_level && this.parent) {
|
60
|
+
return this.parent.assign(name, value, top_level);
|
61
|
+
}
|
62
|
+
return this.variables[name] = {
|
63
|
+
value: value,
|
64
|
+
assigned: true
|
65
|
+
};
|
66
|
+
};
|
67
|
+
// Does this scope reference any variables that need to be declared in the
|
68
|
+
// given function body?
|
69
|
+
Scope.prototype.has_declarations = function has_declarations(body) {
|
70
|
+
return body === this.expressions && this.declared_variables().length;
|
71
|
+
};
|
72
|
+
// Does this scope reference any assignments that need to be declared at the
|
73
|
+
// top of the given function body?
|
74
|
+
Scope.prototype.has_assignments = function has_assignments(body) {
|
75
|
+
return body === this.expressions && this.assigned_variables().length;
|
76
|
+
};
|
77
|
+
// Return the list of variables first declared in current scope.
|
78
|
+
Scope.prototype.declared_variables = function declared_variables() {
|
79
|
+
var __a, __b, key, val;
|
80
|
+
return ((function() {
|
81
|
+
__a = []; __b = this.variables;
|
82
|
+
for (key in __b) {
|
83
|
+
val = __b[key];
|
84
|
+
if (__hasProp.call(__b, key)) {
|
85
|
+
if (val === 'var') {
|
86
|
+
__a.push(key);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
return __a;
|
91
|
+
}).call(this)).sort();
|
92
|
+
};
|
93
|
+
// Return the list of variables that are supposed to be assigned at the top
|
94
|
+
// of scope.
|
95
|
+
Scope.prototype.assigned_variables = function assigned_variables() {
|
96
|
+
var __a, __b, key, val;
|
97
|
+
return ((function() {
|
98
|
+
__a = []; __b = this.variables;
|
99
|
+
for (key in __b) {
|
100
|
+
val = __b[key];
|
101
|
+
if (__hasProp.call(__b, key)) {
|
102
|
+
if (val.assigned) {
|
103
|
+
__a.push([key, val.value]);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return __a;
|
108
|
+
}).call(this)).sort();
|
109
|
+
};
|
110
|
+
Scope.prototype.compiled_declarations = function compiled_declarations() {
|
111
|
+
return this.declared_variables().join(', ');
|
112
|
+
};
|
113
|
+
Scope.prototype.compiled_assignments = function compiled_assignments() {
|
114
|
+
var __a, __b, __c, t;
|
115
|
+
return ((function() {
|
116
|
+
__a = []; __b = this.assigned_variables();
|
117
|
+
for (__c = 0; __c < __b.length; __c++) {
|
118
|
+
t = __b[__c];
|
119
|
+
__a.push(t[0] + ' = ' + t[1]);
|
120
|
+
}
|
121
|
+
return __a;
|
122
|
+
}).call(this)).join(', ');
|
123
|
+
};
|
124
|
+
// Helper functions:
|
125
|
+
// The next character alphabetically, to produce the following string.
|
126
|
+
succ = function succ(str) {
|
127
|
+
return str.slice(0, str.length - 1) + String.fromCharCode(str.charCodeAt(str.length - 1) + 1);
|
128
|
+
};
|
129
|
+
})();
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module StyleScript
|
2
|
+
|
3
|
+
# Scope objects form a tree corresponding to the shape of the function
|
4
|
+
# definitions present in the script. They provide lexical scope, to determine
|
5
|
+
# whether a variable has been seen before or if it needs to be declared.
|
6
|
+
class Scope
|
7
|
+
|
8
|
+
attr_reader :parent, :expressions, :function, :variables, :temp_variable
|
9
|
+
|
10
|
+
# Initialize a scope with its parent, for lookups up the chain,
|
11
|
+
# as well as the Expressions body where it should declare its variables,
|
12
|
+
# and the function that it wraps.
|
13
|
+
def initialize(parent, expressions, function)
|
14
|
+
@parent, @expressions, @function = parent, expressions, function
|
15
|
+
@variables = {}
|
16
|
+
@temp_variable = @parent ? @parent.temp_variable.dup : '__a'
|
17
|
+
end
|
18
|
+
|
19
|
+
# Look up a variable in lexical scope, or declare it if not found.
|
20
|
+
def find(name, remote=false)
|
21
|
+
found = check(name)
|
22
|
+
return found if found || remote
|
23
|
+
@variables[name.to_sym] = :var
|
24
|
+
found
|
25
|
+
end
|
26
|
+
|
27
|
+
# Define a local variable as originating from a parameter in current scope
|
28
|
+
# -- no var required.
|
29
|
+
def parameter(name)
|
30
|
+
@variables[name.to_sym] = :param
|
31
|
+
end
|
32
|
+
|
33
|
+
# Just check to see if a variable has already been declared.
|
34
|
+
def check(name)
|
35
|
+
return true if @variables[name.to_sym]
|
36
|
+
!!(@parent && @parent.check(name))
|
37
|
+
end
|
38
|
+
|
39
|
+
# You can reset a found variable on the immediate scope.
|
40
|
+
def reset(name)
|
41
|
+
@variables[name.to_sym] = false
|
42
|
+
end
|
43
|
+
|
44
|
+
# Find an available, short, name for a compiler-generated variable.
|
45
|
+
def free_variable
|
46
|
+
@temp_variable.succ! while check(@temp_variable)
|
47
|
+
@variables[@temp_variable.to_sym] = :var
|
48
|
+
Value.new(@temp_variable.dup)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Ensure that an assignment is made at the top of scope (or top-level
|
52
|
+
# scope, if requested).
|
53
|
+
def assign(name, value, top=false)
|
54
|
+
return @parent.assign(name, value, top) if top && @parent
|
55
|
+
@variables[name.to_sym] = Value.new(value)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Does this scope reference any variables that need to be declared in the
|
59
|
+
# given function body?
|
60
|
+
def declarations?(body)
|
61
|
+
!declared_variables.empty? && body == @expressions
|
62
|
+
end
|
63
|
+
|
64
|
+
# Does this scope reference any assignments that need to be declared at the
|
65
|
+
# top of the given function body?
|
66
|
+
def assignments?(body)
|
67
|
+
!assigned_variables.empty? && body == @expressions
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the list of variables first declared in current scope.
|
71
|
+
def declared_variables
|
72
|
+
@variables.select {|k, v| v == :var }.map {|pair| pair[0].to_s }.sort
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return the list of variables that are supposed to be assigned at the top
|
76
|
+
# of scope.
|
77
|
+
def assigned_variables
|
78
|
+
@variables.select {|k, v| v.is_a?(Value) }.sort_by {|pair| pair[0].to_s }
|
79
|
+
end
|
80
|
+
|
81
|
+
def compiled_declarations
|
82
|
+
declared_variables.join(', ')
|
83
|
+
end
|
84
|
+
|
85
|
+
def compiled_assignments
|
86
|
+
assigned_variables.map {|name, val| "#{name} = #{val}"}.join(', ')
|
87
|
+
end
|
88
|
+
|
89
|
+
def inspect
|
90
|
+
"<Scope:#{__id__} #{@variables.inspect}>"
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
(function(){
|
2
|
+
var File, OS, Readline, checkForErrors, stylePath, factories, loader, puts;
|
3
|
+
// The Narwhal-compatibility wrapper for StyleScript.
|
4
|
+
// Require external dependencies.
|
5
|
+
OS = require('os');
|
6
|
+
File = require('file');
|
7
|
+
Readline = require('readline');
|
8
|
+
// The path to the StyleScript Compiler.
|
9
|
+
stylePath = File.path(module.path).dirname().dirname().dirname().dirname().join('bin', 'style');
|
10
|
+
// Our general-purpose error handler.
|
11
|
+
checkForErrors = function checkForErrors(styleProcess) {
|
12
|
+
if (styleProcess.wait() === 0) {
|
13
|
+
return true;
|
14
|
+
}
|
15
|
+
system.stderr.print(styleProcess.stderr.read());
|
16
|
+
throw new Error("StyleScript compile error");
|
17
|
+
};
|
18
|
+
// Alias print to "puts", for Node.js compatibility:
|
19
|
+
puts = print;
|
20
|
+
// Run a simple REPL, round-tripping to the StyleScript compiler for every
|
21
|
+
// command.
|
22
|
+
exports.run = function run(args) {
|
23
|
+
var __a, __b, i, path, result;
|
24
|
+
if (args.length) {
|
25
|
+
__a = args;
|
26
|
+
for (i = 0; i < __a.length; i++) {
|
27
|
+
path = __a[i];
|
28
|
+
exports.evalCS(File.read(path));
|
29
|
+
delete args[i];
|
30
|
+
}
|
31
|
+
return true;
|
32
|
+
}
|
33
|
+
__b = [];
|
34
|
+
while (true) {
|
35
|
+
__b.push((function() {
|
36
|
+
try {
|
37
|
+
system.stdout.write('style> ').flush();
|
38
|
+
result = exports.evalCS(Readline.readline(), ['--globals']);
|
39
|
+
if (result !== undefined) {
|
40
|
+
return print(result);
|
41
|
+
}
|
42
|
+
} catch (e) {
|
43
|
+
return print(e);
|
44
|
+
}
|
45
|
+
}).call(this));
|
46
|
+
}
|
47
|
+
return __b;
|
48
|
+
};
|
49
|
+
// Compile a given StyleScript file into JavaScript.
|
50
|
+
exports.compileFile = function compileFile(path) {
|
51
|
+
var style;
|
52
|
+
style = OS.popen([stylePath, "--print", "--no-wrap", path]);
|
53
|
+
checkForErrors(style);
|
54
|
+
return style.stdout.read();
|
55
|
+
};
|
56
|
+
// Compile a string of StyleScript into JavaScript.
|
57
|
+
exports.compile = function compile(source, flags) {
|
58
|
+
var style;
|
59
|
+
style = OS.popen([stylePath, "--eval", "--no-wrap"].concat(flags || []));
|
60
|
+
style.stdin.write(source).flush().close();
|
61
|
+
checkForErrors(style);
|
62
|
+
return style.stdout.read();
|
63
|
+
};
|
64
|
+
// Evaluating a string of StyleScript first compiles it externally.
|
65
|
+
exports.evalCS = function evalCS(source, flags) {
|
66
|
+
return eval(exports.compile(source, flags));
|
67
|
+
};
|
68
|
+
// Make a factory for the StyleScript environment.
|
69
|
+
exports.makeNarwhalFactory = function makeNarwhalFactory(path) {
|
70
|
+
var code, factoryText;
|
71
|
+
code = exports.compileFile(path);
|
72
|
+
factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
|
73
|
+
if (system.engine === "rhino") {
|
74
|
+
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
|
75
|
+
} else {
|
76
|
+
// eval requires parentheses, but parentheses break compileFunction.
|
77
|
+
return eval("(" + factoryText + ")");
|
78
|
+
}
|
79
|
+
};
|
80
|
+
// The Narwhal loader for '.style' files.
|
81
|
+
factories = {
|
82
|
+
};
|
83
|
+
loader = {
|
84
|
+
};
|
85
|
+
// Reload the style-script environment from source.
|
86
|
+
loader.reload = function reload(topId, path) {
|
87
|
+
return factories[topId] = function() {
|
88
|
+
return exports.makeNarwhalFactory(path);
|
89
|
+
};
|
90
|
+
};
|
91
|
+
// Ensure that the style-script environment is loaded.
|
92
|
+
loader.load = function load(topId, path) {
|
93
|
+
return factories[topId] = factories[topId] || this.reload(topId, path);
|
94
|
+
};
|
95
|
+
require.loader.loaders.unshift([".style", loader]);
|
96
|
+
})();
|
@@ -0,0 +1,50 @@
|
|
1
|
+
(function(){
|
2
|
+
var compiler, path;
|
3
|
+
// Executes the `style` Ruby program to convert from StyleScript to JavaScript.
|
4
|
+
path = require('path');
|
5
|
+
// The path to the StyleScript executable.
|
6
|
+
compiler = path.normalize(path.dirname(__filename) + '/../../bin/style');
|
7
|
+
// Compile a string over stdin, with global variables, for the REPL.
|
8
|
+
exports.compile = function compile(code, callback) {
|
9
|
+
var style, js;
|
10
|
+
js = '';
|
11
|
+
style = process.createChildProcess(compiler, ['--eval', '--no-wrap', '--globals']);
|
12
|
+
style.addListener('output', function(results) {
|
13
|
+
if ((typeof results !== "undefined" && results !== null)) {
|
14
|
+
return js += results;
|
15
|
+
}
|
16
|
+
});
|
17
|
+
style.addListener('exit', function() {
|
18
|
+
return callback(js);
|
19
|
+
});
|
20
|
+
style.write(code);
|
21
|
+
return style.close();
|
22
|
+
};
|
23
|
+
// Compile a list of StyleScript files on disk.
|
24
|
+
exports.compile_files = function compile_files(paths, callback) {
|
25
|
+
var style, exit_ran, js;
|
26
|
+
js = '';
|
27
|
+
style = process.createChildProcess(compiler, ['--print'].concat(paths));
|
28
|
+
style.addListener('output', function(results) {
|
29
|
+
if ((typeof results !== "undefined" && results !== null)) {
|
30
|
+
return js += results;
|
31
|
+
}
|
32
|
+
});
|
33
|
+
// NB: we have to add a mutex to make sure it doesn't get called twice.
|
34
|
+
exit_ran = false;
|
35
|
+
style.addListener('exit', function() {
|
36
|
+
if (exit_ran) {
|
37
|
+
return null;
|
38
|
+
}
|
39
|
+
exit_ran = true;
|
40
|
+
return callback(js);
|
41
|
+
});
|
42
|
+
return style.addListener('error', function(message) {
|
43
|
+
if (!(message)) {
|
44
|
+
return null;
|
45
|
+
}
|
46
|
+
puts(message);
|
47
|
+
throw new Error("StyleScript compile error");
|
48
|
+
});
|
49
|
+
};
|
50
|
+
})();
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module StyleScript
|
2
|
+
|
3
|
+
# Instead of producing raw Ruby objects, the Lexer produces values of this
|
4
|
+
# class, wrapping native objects tagged with line number information.
|
5
|
+
# Values masquerade as both strings and nodes -- being used both as nodes in
|
6
|
+
# the AST, and as literally-interpolated values in the generated code.
|
7
|
+
class Value
|
8
|
+
attr_reader :value, :line
|
9
|
+
|
10
|
+
def initialize(value, line=nil)
|
11
|
+
@value, @line = value, line
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_str
|
15
|
+
@value.to_s
|
16
|
+
end
|
17
|
+
alias_method :to_s, :to_str
|
18
|
+
|
19
|
+
def to_sym
|
20
|
+
to_str.to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
def compile(o={})
|
24
|
+
to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
@value.inspect
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(other)
|
32
|
+
@value == other
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](index)
|
36
|
+
@value[index]
|
37
|
+
end
|
38
|
+
|
39
|
+
def eql?(other)
|
40
|
+
@value.eql?(other)
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash
|
44
|
+
@value.hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def match(regex)
|
48
|
+
@value.match(regex)
|
49
|
+
end
|
50
|
+
|
51
|
+
def children
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
|
55
|
+
def statement_only?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def contains?
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|