package xhl.core.validator;

import java.util.List;

import xhl.core.GenericModule;
import xhl.core.Language;
import xhl.core.Module;
import xhl.core.elements.Block;
import xhl.core.elements.Symbol;
import xhl.core.validator.ElementSchema.DefSpec;
import xhl.core.validator.ElementSchema.ParamSpec;

import static com.google.common.base.Preconditions.checkArgument;

public class ValidatorLanguage extends GenericModule implements Language {

    private ElementSchema currentElement;
    private final Schema schema = new Schema();

    public ValidatorLanguage() {
        for (Type type : Type.defaultTypes) {
            addSymbol(type.getName(), type);
        }
    }

    @Element(evaluateArgs = false)
    public void element(Symbol name, Block blk) {
        currentElement = new ElementSchema(name);
        schema.put(currentElement);
        evaluator.eval(blk);
    }

    @Element
    public void params(List<ParamSpec> args) {
        currentElement.setParams(args);
    }

    @Element
    public ParamSpec val(Type type) {
        return ParamSpec.val(type);
    }

    @Element
    public ParamSpec sym(Type type) {
        return ParamSpec.sym(type);
    }

    @Element
    public ParamSpec variadic(ParamSpec param) {
        return ParamSpec.variadic(param);
    }
    @Element
    public ParamSpec block(ParamSpec param) {
        return ParamSpec.block(param);
    }

    @Element
    public void type(Type type) {
        currentElement.setType(type);
    }

    @Element
    public void defines(double arg, Type type) {
        checkArgument(arg % 1 == 0);
        DefSpec def = new DefSpec((int) arg, type);
        currentElement.addDefine(def);
    }

    @Element
    public void defines_backward(double arg, Type type) {
        checkArgument(arg % 1 == 0);
        DefSpec def = new DefSpec((int) arg, type, true);
        currentElement.addDefine(def);
    }

    @Element
    public void newtype(@Symbolic Symbol name) {
        evaluator.putSymbol(name, new Type(name));
    }

    @Override
    public Module[] getModules() {
        return new Module[] { this };
    }

    public Schema getReadSchema() {
        return schema;
    }
}

@@ -26,32 +26,8 @@
 r;%0A%0A
-import java.util.List;%0A%0A
 impo
@@ -269,16 +269,64 @@
 mSpec;%0A%0A
+import java.util.Deque;%0Aimport java.util.List;%0A%0A
 import s
@@ -382,16 +382,77 @@
 rgument;
+%0Aimport static com.google.common.collect.Lists.newLinkedList;
 %0A%0Apublic
@@ -520,16 +520,89 @@
 guage %7B%0A
+    /**%0A     * A stack representing currently processed elements.%0A     */
 %0A    pri
@@ -606,16 +606,22 @@
 private 
+Deque%3C
 ElementS
@@ -625,16 +625,17 @@
 ntSchema
+%3E
  current
@@ -641,16 +641,34 @@
 tElement
+ = newLinkedList()
 ;%0A    pr
@@ -958,19 +958,22 @@
 tElement
- = 
+.push(
 new Elem
@@ -987,16 +987,17 @@
 ma(name)
+)
 ;%0A      
@@ -1023,16 +1023,23 @@
 tElement
+.peek()
 );%0A     
@@ -1062,16 +1062,49 @@
 l(blk);%0A
+        currentElement.remove();%0A
     %7D%0A%0A 
@@ -1185,16 +1185,23 @@
 Element.
+peek().
 setParam
@@ -1510,24 +1510,25 @@
 ram);%0A    %7D%0A
+%0A
     @Element
@@ -1690,16 +1690,23 @@
 Element.
+peek().
 setType(
@@ -1885,32 +1885,39 @@
  currentElement.
+peek().
 addDefine(def);%0A
@@ -2112,16 +2112,23 @@
 Element.
+peek().
 addDefin
@@ -2342,16 +2342,13 @@
 le%5B%5D
- %7B 
+%7B
 this
- 
 %7D;%0A 

Store current elements in a stack