sassc 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +21 -0
- data/ext/libsass/.editorconfig +15 -0
- data/ext/libsass/.gitattributes +2 -0
- data/ext/libsass/.gitignore +61 -0
- data/ext/libsass/.travis.yml +38 -0
- data/ext/libsass/COPYING +25 -0
- data/ext/libsass/INSTALL +1 -0
- data/ext/libsass/LICENSE +25 -0
- data/ext/libsass/Makefile +223 -0
- data/ext/libsass/Makefile.am +145 -0
- data/ext/libsass/Readme.md +93 -0
- data/ext/libsass/appveyor.yml +76 -0
- data/ext/libsass/ast.cpp +581 -0
- data/ext/libsass/ast.hpp +1949 -0
- data/ext/libsass/ast_def_macros.hpp +16 -0
- data/ext/libsass/ast_factory.hpp +87 -0
- data/ext/libsass/ast_fwd_decl.hpp +72 -0
- data/ext/libsass/b64/cencode.h +32 -0
- data/ext/libsass/b64/encode.h +77 -0
- data/ext/libsass/backtrace.hpp +81 -0
- data/ext/libsass/base64vlq.cpp +43 -0
- data/ext/libsass/base64vlq.hpp +28 -0
- data/ext/libsass/bind.cpp +187 -0
- data/ext/libsass/bind.hpp +18 -0
- data/ext/libsass/cencode.c +102 -0
- data/ext/libsass/color_names.hpp +324 -0
- data/ext/libsass/configure.ac +130 -0
- data/ext/libsass/constants.cpp +144 -0
- data/ext/libsass/constants.hpp +145 -0
- data/ext/libsass/context.cpp +507 -0
- data/ext/libsass/context.hpp +150 -0
- data/ext/libsass/contextualize.cpp +157 -0
- data/ext/libsass/contextualize.hpp +65 -0
- data/ext/libsass/copy_c_str.cpp +13 -0
- data/ext/libsass/copy_c_str.hpp +5 -0
- data/ext/libsass/debug.hpp +39 -0
- data/ext/libsass/environment.hpp +75 -0
- data/ext/libsass/error_handling.cpp +28 -0
- data/ext/libsass/error_handling.hpp +28 -0
- data/ext/libsass/eval.cpp +1149 -0
- data/ext/libsass/eval.hpp +80 -0
- data/ext/libsass/expand.cpp +430 -0
- data/ext/libsass/expand.hpp +77 -0
- data/ext/libsass/extconf.rb +6 -0
- data/ext/libsass/extend.cpp +1962 -0
- data/ext/libsass/extend.hpp +50 -0
- data/ext/libsass/file.cpp +291 -0
- data/ext/libsass/file.hpp +18 -0
- data/ext/libsass/functions.cpp +1565 -0
- data/ext/libsass/functions.hpp +187 -0
- data/ext/libsass/inspect.cpp +727 -0
- data/ext/libsass/inspect.hpp +108 -0
- data/ext/libsass/json.cpp +1411 -0
- data/ext/libsass/json.hpp +117 -0
- data/ext/libsass/kwd_arg_macros.hpp +23 -0
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/mapping.hpp +17 -0
- data/ext/libsass/memory_manager.hpp +54 -0
- data/ext/libsass/node.cpp +251 -0
- data/ext/libsass/node.hpp +122 -0
- data/ext/libsass/operation.hpp +153 -0
- data/ext/libsass/output_compressed.cpp +401 -0
- data/ext/libsass/output_compressed.hpp +95 -0
- data/ext/libsass/output_nested.cpp +364 -0
- data/ext/libsass/output_nested.hpp +108 -0
- data/ext/libsass/parser.cpp +2016 -0
- data/ext/libsass/parser.hpp +264 -0
- data/ext/libsass/paths.hpp +69 -0
- data/ext/libsass/position.hpp +22 -0
- data/ext/libsass/posix/getopt.c +562 -0
- data/ext/libsass/posix/getopt.h +95 -0
- data/ext/libsass/prelexer.cpp +688 -0
- data/ext/libsass/prelexer.hpp +513 -0
- data/ext/libsass/remove_placeholders.cpp +59 -0
- data/ext/libsass/remove_placeholders.hpp +43 -0
- data/ext/libsass/res/resource.rc +35 -0
- data/ext/libsass/sass.cpp +33 -0
- data/ext/libsass/sass.h +60 -0
- data/ext/libsass/sass2scss.cpp +834 -0
- data/ext/libsass/sass2scss.h +110 -0
- data/ext/libsass/sass_context.cpp +709 -0
- data/ext/libsass/sass_context.h +120 -0
- data/ext/libsass/sass_functions.cpp +137 -0
- data/ext/libsass/sass_functions.h +90 -0
- data/ext/libsass/sass_interface.cpp +277 -0
- data/ext/libsass/sass_interface.h +97 -0
- data/ext/libsass/sass_util.cpp +136 -0
- data/ext/libsass/sass_util.hpp +259 -0
- data/ext/libsass/sass_values.cpp +337 -0
- data/ext/libsass/sass_values.h +124 -0
- data/ext/libsass/script/bootstrap +10 -0
- data/ext/libsass/script/branding +10 -0
- data/ext/libsass/script/ci-build-libsass +72 -0
- data/ext/libsass/script/ci-install-compiler +4 -0
- data/ext/libsass/script/ci-install-deps +19 -0
- data/ext/libsass/script/ci-report-coverage +25 -0
- data/ext/libsass/script/coveralls-debug +32 -0
- data/ext/libsass/script/spec +5 -0
- data/ext/libsass/script/tap-driver +652 -0
- data/ext/libsass/script/tap-runner +1 -0
- data/ext/libsass/source_map.cpp +133 -0
- data/ext/libsass/source_map.hpp +46 -0
- data/ext/libsass/subset_map.hpp +145 -0
- data/ext/libsass/support/libsass.pc.in +11 -0
- data/ext/libsass/test-driver +127 -0
- data/ext/libsass/test/test_node.cpp +98 -0
- data/ext/libsass/test/test_paths.cpp +29 -0
- data/ext/libsass/test/test_selector_difference.cpp +28 -0
- data/ext/libsass/test/test_specificity.cpp +28 -0
- data/ext/libsass/test/test_subset_map.cpp +472 -0
- data/ext/libsass/test/test_superselector.cpp +71 -0
- data/ext/libsass/test/test_unification.cpp +33 -0
- data/ext/libsass/to_c.cpp +61 -0
- data/ext/libsass/to_c.hpp +44 -0
- data/ext/libsass/to_string.cpp +29 -0
- data/ext/libsass/to_string.hpp +32 -0
- data/ext/libsass/token.hpp +32 -0
- data/ext/libsass/units.cpp +54 -0
- data/ext/libsass/units.hpp +10 -0
- data/ext/libsass/utf8.h +34 -0
- data/ext/libsass/utf8/checked.h +327 -0
- data/ext/libsass/utf8/core.h +329 -0
- data/ext/libsass/utf8/unchecked.h +228 -0
- data/ext/libsass/utf8_string.cpp +102 -0
- data/ext/libsass/utf8_string.hpp +36 -0
- data/ext/libsass/util.cpp +189 -0
- data/ext/libsass/util.hpp +26 -0
- data/ext/libsass/win/libsass.filters +291 -0
- data/ext/libsass/win/libsass.sln +28 -0
- data/ext/libsass/win/libsass.vcxproj +255 -0
- data/lib/sassc.rb +6 -0
- data/lib/sassc/engine.rb +13 -0
- data/lib/sassc/native.rb +44 -0
- data/lib/sassc/native/native_context_api.rb +140 -0
- data/lib/sassc/native/native_functions_api.rb +41 -0
- data/lib/sassc/native/sass_input_style.rb +11 -0
- data/lib/sassc/native/sass_output_style.rb +10 -0
- data/lib/sassc/native/sass_value.rb +95 -0
- data/lib/sassc/native/string_list.rb +8 -0
- data/lib/sassc/version.rb +3 -0
- data/sassc.gemspec +43 -0
- data/test/smoke_test.rb +171 -0
- data/test/test_helper.rb +4 -0
- metadata +281 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#ifndef SASS_C_INTERFACE
|
|
2
|
+
#define SASS_C_INTERFACE
|
|
3
|
+
|
|
4
|
+
#include <stddef.h>
|
|
5
|
+
#include <stdbool.h>
|
|
6
|
+
#include "sass.h"
|
|
7
|
+
|
|
8
|
+
#ifdef __cplusplus
|
|
9
|
+
extern "C" {
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// Please ensure there are no null values.
|
|
14
|
+
// Thar be dragons.
|
|
15
|
+
struct sass_options {
|
|
16
|
+
// Output style for the generated css code
|
|
17
|
+
// A value from above SASS_STYLE_* constants
|
|
18
|
+
int output_style;
|
|
19
|
+
// If you want inline source comments
|
|
20
|
+
bool source_comments;
|
|
21
|
+
// Path to source map file
|
|
22
|
+
// Enables the source map generating
|
|
23
|
+
// Used to create sourceMappingUrl
|
|
24
|
+
const char* source_map_file;
|
|
25
|
+
// Disable sourceMappingUrl in css output
|
|
26
|
+
bool omit_source_map_url;
|
|
27
|
+
// embed sourceMappingUrl as data uri
|
|
28
|
+
bool source_map_embed;
|
|
29
|
+
// embed include contents in maps
|
|
30
|
+
bool source_map_contents;
|
|
31
|
+
// Treat source_string as sass (as opposed to scss)
|
|
32
|
+
bool is_indented_syntax_src;
|
|
33
|
+
// Colon-separated list of paths
|
|
34
|
+
// Semicolon-separated on Windows
|
|
35
|
+
const char* include_paths;
|
|
36
|
+
// For the image-url Sass function
|
|
37
|
+
const char* image_path;
|
|
38
|
+
// Precision for outputting fractional numbers
|
|
39
|
+
int precision;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
struct sass_context {
|
|
43
|
+
const char* input_path;
|
|
44
|
+
const char* output_path;
|
|
45
|
+
const char* source_string;
|
|
46
|
+
char* output_string;
|
|
47
|
+
char* source_map_string;
|
|
48
|
+
struct sass_options options;
|
|
49
|
+
int error_status;
|
|
50
|
+
char* error_message;
|
|
51
|
+
Sass_C_Function_List c_functions;
|
|
52
|
+
char** included_files;
|
|
53
|
+
int num_included_files;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
struct sass_file_context {
|
|
57
|
+
const char* input_path;
|
|
58
|
+
const char* output_path;
|
|
59
|
+
char* output_string;
|
|
60
|
+
char* source_map_string;
|
|
61
|
+
struct sass_options options;
|
|
62
|
+
int error_status;
|
|
63
|
+
char* error_message;
|
|
64
|
+
Sass_C_Function_List c_functions;
|
|
65
|
+
char** included_files;
|
|
66
|
+
int num_included_files;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
struct sass_folder_context {
|
|
70
|
+
const char* search_path;
|
|
71
|
+
const char* output_path;
|
|
72
|
+
struct sass_options options;
|
|
73
|
+
int error_status;
|
|
74
|
+
char* error_message;
|
|
75
|
+
Sass_C_Function_List c_functions;
|
|
76
|
+
char** included_files;
|
|
77
|
+
int num_included_files;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
struct sass_context* sass_new_context (void);
|
|
81
|
+
struct sass_file_context* sass_new_file_context (void);
|
|
82
|
+
struct sass_folder_context* sass_new_folder_context (void);
|
|
83
|
+
|
|
84
|
+
void sass_free_context (struct sass_context* ctx);
|
|
85
|
+
void sass_free_file_context (struct sass_file_context* ctx);
|
|
86
|
+
void sass_free_folder_context(struct sass_folder_context* ctx);
|
|
87
|
+
|
|
88
|
+
int sass_compile (struct sass_context* ctx);
|
|
89
|
+
int sass_compile_file (struct sass_file_context* ctx);
|
|
90
|
+
int sass_compile_folder (struct sass_folder_context* ctx);
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#ifdef __cplusplus
|
|
94
|
+
}
|
|
95
|
+
#endif
|
|
96
|
+
|
|
97
|
+
#endif
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#ifndef SASS_AST
|
|
2
|
+
#include "node.hpp"
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#include "to_string.hpp"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
namespace Sass {
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
This is the equivalent of ruby's Sass::Util.paths.
|
|
13
|
+
|
|
14
|
+
# Return an array of all possible paths through the given arrays.
|
|
15
|
+
#
|
|
16
|
+
# @param arrs [NodeCollection<NodeCollection<Node>>]
|
|
17
|
+
# @return [NodeCollection<NodeCollection<Node>>]
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# paths([[1, 2], [3, 4], [5]]) #=>
|
|
21
|
+
# # [[1, 3, 5],
|
|
22
|
+
# # [2, 3, 5],
|
|
23
|
+
# # [1, 4, 5],
|
|
24
|
+
# # [2, 4, 5]]
|
|
25
|
+
|
|
26
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
|
27
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
|
28
|
+
|
|
29
|
+
def paths(arrs)
|
|
30
|
+
// I changed the inject and maps to an iterative approach to make it easier to implement in C++
|
|
31
|
+
loopStart = [[]]
|
|
32
|
+
|
|
33
|
+
for arr in arrs do
|
|
34
|
+
permutations = []
|
|
35
|
+
for e in arr do
|
|
36
|
+
for path in loopStart do
|
|
37
|
+
permutations.push(path + [e])
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
loopStart = permutations
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
*/
|
|
44
|
+
Node paths(const Node& arrs, Context& ctx) {
|
|
45
|
+
To_String to_string;
|
|
46
|
+
|
|
47
|
+
Node loopStart = Node::createCollection();
|
|
48
|
+
loopStart.collection()->push_back(Node::createCollection());
|
|
49
|
+
|
|
50
|
+
for (NodeDeque::iterator arrsIter = arrs.collection()->begin(), arrsEndIter = arrs.collection()->end();
|
|
51
|
+
arrsIter != arrsEndIter; ++arrsIter) {
|
|
52
|
+
|
|
53
|
+
Node& arr = *arrsIter;
|
|
54
|
+
|
|
55
|
+
Node permutations = Node::createCollection();
|
|
56
|
+
|
|
57
|
+
for (NodeDeque::iterator arrIter = arr.collection()->begin(), arrIterEnd = arr.collection()->end();
|
|
58
|
+
arrIter != arrIterEnd; ++arrIter) {
|
|
59
|
+
|
|
60
|
+
Node& e = *arrIter;
|
|
61
|
+
|
|
62
|
+
for (NodeDeque::iterator loopStartIter = loopStart.collection()->begin(), loopStartIterEnd = loopStart.collection()->end();
|
|
63
|
+
loopStartIter != loopStartIterEnd; ++loopStartIter) {
|
|
64
|
+
|
|
65
|
+
Node& path = *loopStartIter;
|
|
66
|
+
|
|
67
|
+
Node newPermutation = Node::createCollection();
|
|
68
|
+
newPermutation.plus(path);
|
|
69
|
+
newPermutation.collection()->push_back(e);
|
|
70
|
+
|
|
71
|
+
permutations.collection()->push_back(newPermutation);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
loopStart = permutations;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return loopStart;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
|
|
84
|
+
Sass::Util.flatten requires the number of levels to flatten, while
|
|
85
|
+
[].flatten doesn't and will flatten the entire array. This function
|
|
86
|
+
supports both.
|
|
87
|
+
|
|
88
|
+
# Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
|
|
89
|
+
#
|
|
90
|
+
# @param arr [NodeCollection] The array to flatten
|
|
91
|
+
# @param n [int] The number of levels to flatten
|
|
92
|
+
# @return [NodeCollection] The flattened array
|
|
93
|
+
|
|
94
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
|
95
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
|
96
|
+
|
|
97
|
+
def flatten(arr, n = -1)
|
|
98
|
+
if n != -1 and n == 0 then
|
|
99
|
+
return arr
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
flattened = []
|
|
103
|
+
|
|
104
|
+
for e in arr do
|
|
105
|
+
if e.is_a?(Array) then
|
|
106
|
+
flattened.concat(flatten(e, n - 1))
|
|
107
|
+
else
|
|
108
|
+
flattened << e
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return flattened
|
|
113
|
+
end
|
|
114
|
+
*/
|
|
115
|
+
Node flatten(const Node& arr, Context& ctx, int n = -1) {
|
|
116
|
+
if (n != -1 && n == 0) {
|
|
117
|
+
return arr;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Node flattened = Node::createCollection();
|
|
121
|
+
|
|
122
|
+
for (NodeDeque::iterator iter = arr.collection()->begin(), iterEnd = arr.collection()->end();
|
|
123
|
+
iter != iterEnd; iter++) {
|
|
124
|
+
Node& e = *iter;
|
|
125
|
+
|
|
126
|
+
if (e.isCollection()) {
|
|
127
|
+
Node recurseFlattened = flatten(e, ctx, n - 1);
|
|
128
|
+
flattened.collection()->insert(flattened.collection()->end(), recurseFlattened.collection()->begin(), recurseFlattened.collection()->end());
|
|
129
|
+
} else {
|
|
130
|
+
flattened.collection()->push_back(e);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return flattened;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#include <deque>
|
|
2
|
+
#include <iostream>
|
|
3
|
+
|
|
4
|
+
#ifndef SASS_AST
|
|
5
|
+
#include "ast.hpp"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include "node.hpp"
|
|
9
|
+
#include "debug.hpp"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
namespace Sass {
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
using namespace std;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
This is for ports of functions in the Sass:Util module.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
# Return a Node collection of all possible paths through the given Node collection of Node collections.
|
|
25
|
+
#
|
|
26
|
+
# @param arrs [NodeCollection<NodeCollection<Node>>]
|
|
27
|
+
# @return [NodeCollection<NodeCollection<Node>>]
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# paths([[1, 2], [3, 4], [5]]) #=>
|
|
31
|
+
# # [[1, 3, 5],
|
|
32
|
+
# # [2, 3, 5],
|
|
33
|
+
# # [1, 4, 5],
|
|
34
|
+
# # [2, 4, 5]]
|
|
35
|
+
*/
|
|
36
|
+
Node paths(const Node& arrs, Context& ctx);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
This class is a default implementation of a Node comparator that can be passed to the lcs function below.
|
|
41
|
+
It uses operator== for equality comparision. It then returns one if the Nodes are equal.
|
|
42
|
+
*/
|
|
43
|
+
class DefaultLcsComparator {
|
|
44
|
+
public:
|
|
45
|
+
bool operator()(const Node& one, const Node& two, Node& out) const {
|
|
46
|
+
// TODO: Is this the correct C++ interpretation?
|
|
47
|
+
// block ||= proc {|a, b| a == b && a}
|
|
48
|
+
if (one == two) {
|
|
49
|
+
out = one;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
typedef vector<vector<int> > LCSTable;
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
This is the equivalent of ruby's Sass::Util.lcs_backtrace.
|
|
63
|
+
|
|
64
|
+
# Computes a single longest common subsequence for arrays x and y.
|
|
65
|
+
# Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
|
|
66
|
+
*/
|
|
67
|
+
template<typename ComparatorType>
|
|
68
|
+
Node lcs_backtrace(const LCSTable& c, const Node& x, const Node& y, int i, int j, const ComparatorType& comparator) {
|
|
69
|
+
DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
|
|
70
|
+
|
|
71
|
+
if (i == 0 || j == 0) {
|
|
72
|
+
DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
|
|
73
|
+
return Node::createCollection();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
NodeDeque& xChildren = *(x.collection());
|
|
77
|
+
NodeDeque& yChildren = *(y.collection());
|
|
78
|
+
|
|
79
|
+
Node compareOut = Node::createNil();
|
|
80
|
+
if (comparator(xChildren[i], yChildren[j], compareOut)) {
|
|
81
|
+
DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
|
|
82
|
+
Node result = lcs_backtrace(c, x, y, i - 1, j - 1, comparator);
|
|
83
|
+
result.collection()->push_back(compareOut);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (c[i][j - 1] > c[i - 1][j]) {
|
|
88
|
+
DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
|
|
89
|
+
return lcs_backtrace(c, x, y, i, j - 1, comparator);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
DEBUG_PRINTLN(LCS, "FINAL RETURN")
|
|
93
|
+
return lcs_backtrace(c, x, y, i - 1, j, comparator);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
This is the equivalent of ruby's Sass::Util.lcs_table.
|
|
99
|
+
|
|
100
|
+
# Calculates the memoization table for the Least Common Subsequence algorithm.
|
|
101
|
+
# Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
|
|
102
|
+
*/
|
|
103
|
+
template<typename ComparatorType>
|
|
104
|
+
void lcs_table(const Node& x, const Node& y, const ComparatorType& comparator, LCSTable& out) {
|
|
105
|
+
DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
|
|
106
|
+
|
|
107
|
+
NodeDeque& xChildren = *(x.collection());
|
|
108
|
+
NodeDeque& yChildren = *(y.collection());
|
|
109
|
+
|
|
110
|
+
LCSTable c(xChildren.size(), vector<int>(yChildren.size()));
|
|
111
|
+
|
|
112
|
+
// These shouldn't be necessary since the vector will be initialized to 0 already.
|
|
113
|
+
// x.size.times {|i| c[i][0] = 0}
|
|
114
|
+
// y.size.times {|j| c[0][j] = 0}
|
|
115
|
+
|
|
116
|
+
for (size_t i = 1; i < xChildren.size(); i++) {
|
|
117
|
+
for (size_t j = 1; j < yChildren.size(); j++) {
|
|
118
|
+
Node compareOut = Node::createNil();
|
|
119
|
+
|
|
120
|
+
if (comparator(xChildren[i], yChildren[j], compareOut)) {
|
|
121
|
+
c[i][j] = c[i - 1][j - 1] + 1;
|
|
122
|
+
} else {
|
|
123
|
+
c[i][j] = max(c[i][j - 1], c[i - 1][j]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
out = c;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
This is the equivalent of ruby's Sass::Util.lcs.
|
|
134
|
+
|
|
135
|
+
# Computes a single longest common subsequence for `x` and `y`.
|
|
136
|
+
# If there are more than one longest common subsequences,
|
|
137
|
+
# the one returned is that which starts first in `x`.
|
|
138
|
+
|
|
139
|
+
# @param x [NodeCollection]
|
|
140
|
+
# @param y [NodeCollection]
|
|
141
|
+
# @comparator An equality check between elements of `x` and `y`.
|
|
142
|
+
# @return [NodeCollection] The LCS
|
|
143
|
+
|
|
144
|
+
http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
|
|
145
|
+
*/
|
|
146
|
+
template<typename ComparatorType>
|
|
147
|
+
Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
|
|
148
|
+
DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
|
|
149
|
+
|
|
150
|
+
Node newX = Node::createCollection();
|
|
151
|
+
newX.collection()->push_back(Node::createNil());
|
|
152
|
+
newX.plus(x);
|
|
153
|
+
|
|
154
|
+
Node newY = Node::createCollection();
|
|
155
|
+
newY.collection()->push_back(Node::createNil());
|
|
156
|
+
newY.plus(y);
|
|
157
|
+
|
|
158
|
+
LCSTable table;
|
|
159
|
+
lcs_table(newX, newY, comparator, table);
|
|
160
|
+
|
|
161
|
+
return lcs_backtrace(table, newX, newY, static_cast<int>(newX.collection()->size()) - 1, static_cast<int>(newY.collection()->size()) - 1, comparator);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
|
|
167
|
+
Sass::Util.flatten requires the number of levels to flatten, while
|
|
168
|
+
[].flatten doesn't and will flatten the entire array. This function
|
|
169
|
+
supports both.
|
|
170
|
+
|
|
171
|
+
# Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
|
|
172
|
+
#
|
|
173
|
+
# @param arr [NodeCollection] The array to flatten
|
|
174
|
+
# @param n [int] The number of levels to flatten
|
|
175
|
+
# @return [NodeCollection] The flattened array
|
|
176
|
+
*/
|
|
177
|
+
Node flatten(const Node& arr, Context& ctx, int n = -1);
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
This is the equivalent of ruby's Sass::Util.group_by_to_a.
|
|
182
|
+
|
|
183
|
+
# Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
|
|
184
|
+
# order. Unlike [#hash_to_a], the resulting order isn't sorted key order;
|
|
185
|
+
# instead, it's the same order as `#group_by` has under Ruby 1.9 (key
|
|
186
|
+
# appearance order).
|
|
187
|
+
#
|
|
188
|
+
# @param enum [Enumerable]
|
|
189
|
+
# @return [Array<[Object, Array]>] An array of pairs.
|
|
190
|
+
|
|
191
|
+
TODO: update @param and @return once I know what those are.
|
|
192
|
+
|
|
193
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
|
194
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
|
195
|
+
|
|
196
|
+
def group_by_to_a(enum, &block)
|
|
197
|
+
order = {}
|
|
198
|
+
|
|
199
|
+
arr = []
|
|
200
|
+
|
|
201
|
+
grouped = {}
|
|
202
|
+
|
|
203
|
+
for e in enum do
|
|
204
|
+
key = block[e]
|
|
205
|
+
unless order.include?(key)
|
|
206
|
+
order[key] = order.size
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
if not grouped.has_key?(key) then
|
|
210
|
+
grouped[key] = [e]
|
|
211
|
+
else
|
|
212
|
+
grouped[key].push(e)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
grouped.each do |key, vals|
|
|
217
|
+
arr[order[key]] = [key, vals]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
arr
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
*/
|
|
224
|
+
template<typename EnumType, typename KeyType, typename KeyFunctorType>
|
|
225
|
+
void group_by_to_a(vector<EnumType>& enumeration, KeyFunctorType& keyFunc, vector<pair<KeyType, vector<EnumType> > >& arr /*out*/) {
|
|
226
|
+
|
|
227
|
+
map<unsigned int, KeyType> order;
|
|
228
|
+
|
|
229
|
+
map<KeyType, vector<EnumType> > grouped;
|
|
230
|
+
|
|
231
|
+
for (typename vector<EnumType>::iterator enumIter = enumeration.begin(), enumIterEnd = enumeration.end(); enumIter != enumIterEnd; enumIter++) {
|
|
232
|
+
EnumType& e = *enumIter;
|
|
233
|
+
|
|
234
|
+
KeyType key = keyFunc(e);
|
|
235
|
+
|
|
236
|
+
if (grouped.find(key) == grouped.end()) {
|
|
237
|
+
order.insert(make_pair(order.size(), key));
|
|
238
|
+
|
|
239
|
+
vector<EnumType> newCollection;
|
|
240
|
+
newCollection.push_back(e);
|
|
241
|
+
grouped.insert(make_pair(key, newCollection));
|
|
242
|
+
} else {
|
|
243
|
+
vector<EnumType>& collection = grouped.at(key);
|
|
244
|
+
collection.push_back(e);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (unsigned int index = 0; index < order.size(); index++) {
|
|
249
|
+
KeyType& key = order.at(index);
|
|
250
|
+
vector<EnumType>& values = grouped.at(key);
|
|
251
|
+
|
|
252
|
+
pair<KeyType, vector<EnumType> > grouping = make_pair(key, values);
|
|
253
|
+
|
|
254
|
+
arr.push_back(grouping);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
}
|