Browse Source

Allow using mixins inside mixins

master
Dylan Baker 5 years ago
parent
commit
e415b5b7fd
2 changed files with 53 additions and 9 deletions
  1. 51
    7
      src/ast/mixin.ts
  2. 2
    2
      src/env.ts

+ 51
- 7
src/ast/mixin.ts View File

3
 import Token from '../token';
3
 import Token from '../token';
4
 
4
 
5
 interface Expansion {
5
 interface Expansion {
6
-  rules: (String | EnvError)[];
7
-  children: (String | EnvError)[];
6
+  rules: (string | EnvError)[];
7
+  children: (string | EnvError)[];
8
 }
8
 }
9
 
9
 
10
 export class Mixin {
10
 export class Mixin {
42
       );
42
       );
43
     }
43
     }
44
 
44
 
45
+    const expandedArgs: AST.Node[] = [];
46
+    for (const arg of args) {
47
+      if (arg instanceof AST.Identifier) {
48
+        const lookup = env.get(arg.name);
49
+        if (lookup instanceof EnvError) return lookup;
50
+        expandedArgs.push(lookup);
51
+      }
52
+
53
+      expandedArgs.push(arg);
54
+    }
55
+
45
     const mixinEnv = new Env(env);
56
     const mixinEnv = new Env(env);
46
     this.parameters.forEach((param, index) => {
57
     this.parameters.forEach((param, index) => {
47
-      mixinEnv.set(param.name.value, args[index]);
58
+      mixinEnv.set(param.name.value, expandedArgs[index]);
48
     });
59
     });
49
 
60
 
50
     const rules = this.children
61
     const rules = this.children
51
       .filter((child: AST.Node): child is AST.Rule => child instanceof AST.Rule)
62
       .filter((child: AST.Node): child is AST.Rule => child instanceof AST.Rule)
52
-      .map((child: AST.Rule) => child.compile(mixinEnv, opts));
63
+      .map((rule: AST.Rule) => rule.compile(mixinEnv, opts));
53
 
64
 
54
     const children = this.children
65
     const children = this.children
55
       .filter(
66
       .filter(
56
         (child: AST.Node): child is AST.RuleSet => child instanceof AST.RuleSet
67
         (child: AST.Node): child is AST.RuleSet => child instanceof AST.RuleSet
57
       )
68
       )
58
-      .map((child: AST.RuleSet) => {
59
-        child.selectors.forEach((sel) => (sel.parents = parents));
60
-        return child.compile(mixinEnv, opts);
69
+      .map((ruleSet: AST.RuleSet) => {
70
+        ruleSet.selectors.forEach((sel) => (sel.parents = parents));
71
+        return ruleSet.compile(mixinEnv, opts);
61
       });
72
       });
62
 
73
 
74
+    const applicationExpansions: (Expansion | EnvError)[] = this.children
75
+      .filter(
76
+        (child: AST.Node): child is AST.Application =>
77
+          child instanceof AST.Application
78
+      )
79
+      .map((application: AST.Application) => {
80
+        const mixin = mixinEnv.get(application.name.value);
81
+        if (mixin instanceof EnvError) {
82
+          return mixin;
83
+        } else if (mixin instanceof AST.Mixin) {
84
+          return mixin.expand(mixinEnv, opts, parents, application.arguments);
85
+        } else {
86
+          return new EnvError(1, 'Expected a mixin');
87
+        }
88
+      });
89
+
90
+    const expansionError = applicationExpansions.find(
91
+      (el) => el instanceof EnvError
92
+    );
93
+    if (expansionError) {
94
+      return expansionError;
95
+    }
96
+
97
+    applicationExpansions.forEach((el) => {
98
+      if (!(el instanceof EnvError)) {
99
+        el.rules.forEach((rule) => {
100
+          if (!(rule instanceof EnvError)) {
101
+            rules.push(rule);
102
+          }
103
+        });
104
+      }
105
+    });
106
+
63
     return { rules, children };
107
     return { rules, children };
64
   }
108
   }
65
 }
109
 }

+ 2
- 2
src/env.ts View File

17
 export default class Env {
17
 export default class Env {
18
   public data: { [name: string]: AST.Node };
18
   public data: { [name: string]: AST.Node };
19
 
19
 
20
-  public constructor(parent = {}) {
21
-    this.data = Object.assign({}, parent);
20
+  public constructor(parent?: Env) {
21
+    this.data = parent ? Object.assign({}, parent.data) : {};
22
   }
22
   }
23
 
23
 
24
   public get(name: Token): AST.Node | EnvError {
24
   public get(name: Token): AST.Node | EnvError {

Loading…
Cancel
Save