style-script 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|