Skip to content

template-calls.stx

pdmosses/webdsl-statix/webdslstatix/trans/static-semantics/ui/template-calls.stx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
module 

imports
  static-semantics/actions/functions

  static-semantics/entities/annotations

  static-semantics/types/built-ins

  static-semantics/ui/actions
  static-semantics/ui/attributes

  static-semantics/webdsl-actions
  static-semantics/webdsl-types
  static-semantics/webdsl-ui
  static-semantics/webdsl

rules // template calls

  templateElementOk(s, _, s_pha, TemplateCall2TemplateElement(tc)) :-
    templateCallOk(s, s_pha, tc).

   : scope * scope * TemplateCall
  ajaxTemplateCallOk(s, s_pha, tc) :- templateCallOk_internal(s, s_pha, tc, TRUE()).

   : scope * scope * TemplateCall
  templateCallOk(s, s_pha, tc) :- templateCallOk_internal(s, s_pha, tc, FALSE()).

  // BOOL denotes if template must be ajax enabled
   : scope * scope * TemplateCall * BOOL
  templateCallOk_internal(, s_pha, TemplateCall(TemplateCallId(t), TCallArgs(targs), TCallPropAssigns(propAssigns), TemplateBody(body)), ajax) :-
    templatePropAssignmentsOk(s, propAssigns),
    templateElementsOk(s, s_pha, body),
    templateCallMatchesSig(s, t, targs, ajax).

  // BOOL denotes if template must be ajax enabled
   : scope * string * list(TemplateArgExp) * BOOL
  templateCallMatchesSig(, , , ajax) :- {   }
    argTypes == typesOfTemplateArgExps(s, targs),
    inputTemplateCallOk(s, t, targs, argTypes),
    nameCompatibleSigs == resolveTemplate_internal(s, t, ajax),
    mostSpecificSigs == mostSpecificSigs(argTypes, typeCompatibleSigs(nameCompatibleSigs, argTypes)),
    mostSpecificSigs == [(t', TEMPLATE(_, _, _)) | _] | error $[Cannot resolve template [t] with compatible argument types] @t,
    singleSignature(mostSpecificSigs, "template", t) | error $[Cannot resolve template [t] with compatible argument types] @t,
    @t.ref := t'.

  typesOfTemplateArgExps maps typeOfTemplateArgExp(*, list(*)) = list(*)
   : scope * TemplateArgExp -> TYPE
  typeOfTemplateArgExp(s, Exp(exp))                      = typeOfExp(s, exp).
  typeOfTemplateArgExp(s, TemplateElementsArgument(exp)) = TEMPLATEELEMENTS().
  typeOfTemplateArgExp(s, ExpEntityDerive(_, _))         = UNTYPED() :- // TO-DO
    try { false } | warning $[Derive expressions not implemented yet].

rules // pre-defined template calls

  // elements
  templateCallOk(_, _, TemplateCall(TemplateCallId("elements"), TCallArgs(targs), TCallPropAssigns(propAssigns), TemplateBody(body))) :-
    targs == [] | error $[Cannot pass arguments to passed template elements],
    body == []  | error $[Cannot pass template elements to passed template elements].

  // validation
  templateCallOk(s, _, ValidationErrors(_)).
  templateCallOk(s, _, ValidationErrorsEmpty()).

  // navigatebutton
  templateCallOk(s, s_pha, tc@TemplateCall(TemplateCallId("navigatebutton"), TCallArgs([Exp(ThisCall2Exp(ThisCall("url", _))) | _]), _, _)) :-
    templateCallOk_internal(s, s_pha, tc, FALSE()).

  templateCallOk(, s_pha, tc@TemplateCall(TemplateCallId(t@"navigatebutton"), TCallArgs([Exp(ThisCall2Exp(ThisCall(p, args))) | [Exp(e)]]), _, _)) :-
    typeCompatible(typeOfExp(s, e), string(s)) | error $[Cannot resolve template [t] with compatible argument types] @tc,
    pageCallOk_internal(s, p, args).

rules // navigate calls

  templateElementOk(, _, s_pha, NavigateCall(pc, props, elems)) :-
    pageCallOk(s, pc),
    templatePropAssignmentsOk(s, props),
    templateElementsOk(s, s_pha, elems).

   : scope * PageCall
  pageCallOk(s, PageCall(p, args)) :-
    pageCallOk_internal(s, p, args).

   : scope * string * list(Exp)
  pageCallOk_internal(, , ) :- { }
    pageType(s, p) == PAGE(_, ts) | error $[There is no page with signature [p]] @p, // correct error message for tests
    argTypes == typesOfExps(s, args),
    typesCompatible(argTypes, ts) == TRUE() | error $[Given argument types not compatible with page definition. Got [argTypes] but expected [ts]] @args.

  pageCallOk_internal(_, "root", []). // root page is always accessible from all locations

rules // property assignments

   : scope * list(PropertyAssignment)
  templatePropAssignmentsOk(s, pas) :- templatePropAssignmentsOkNoDuplicates(s, pas, []).

   : scope * list(PropertyAssignment) * list(string)
  templatePropAssignmentsOkNoDuplicates(_, [], _).
  templatePropAssignmentsOkNoDuplicates(, [pa | pas], ) :- {}
    x == templatePropAssignmentOk(s, pa),
    noDuplicatesString(x, xs) | error $[Properties are defined multiple times: [x]] @x, // correct error message for tests
    templatePropAssignmentsOkNoDuplicates(s, pas, [x | xs]).

   : scope * PropertyAssignment -> string // return name of property for duplicate check
  templatePropAssignmentOk(s, _) = "_IGNORE" :- // TO-DO
    try { false } | warning $[This template property assignment is not implemented yet].

  templatePropAssignmentOk(, PropertyAssignment(x, )) = x :-
    typeCompatible(typeOfExp(s, e), string(s)) | error $[Property [x] requires a String value] @e.

  templatePropAssignmentOk(s, PropertySubmit(x, a)) = x :-
    actionCallOrInlineOrExpOk(s, a).

  templatePropAssignmentOk(s, AttributeSelection2PropertyAssignment(AttributeIgnoreDefault(c@"class"))) = "_IGNORE".
  templatePropAssignmentOk(s, AttributeSelection2PropertyAssignment(AttributeIgnoreDefault(c@"style"))) = "_IGNORE".
  templatePropAssignmentOk(s, AttributeSelection2PropertyAssignment(AttributeIgnoreDefault(_))) = "_IGNORE" :-
    false | error $[Only "class" and "style" are implicitly combined with defaults].

  templatePropAssignmentOk(s, CommonAttribute2PropertyAssignment(ca)) = "_IGNORE" :-
    commonAttributeOk(s, ca).

  templatePropAssignmentOk(s, AttributeSelection2PropertyAssignment(AttributeSelection())) = "_IGNORE" :- {  }
    resolveAttributeCollection(s, a) == [(_, a') | _] | error $[Attribute collection [a] is not defined],
    @a.ref := a'.

rules // mutability check for input templates

   : scope * string * list(TemplateArgExp) * list(TYPE)
  inputTemplateCallOk(s, _, _, _). // all other template calls are ok
  inputTemplateCallOk(s, "input", [Exp(e) | _], [t | _]) :- isMutableExp(s, e, t).

   : scope * Exp * TYPE
  isMutableExp(_, , t) :- false | error $[Cannot verify mutability of expression [e]] @e.
  isMutableExp(s, Var(x), t) :- isMutableOrRef(s, x, t).
  isMutableExp(s, Cast(_, sort), t) :- typeOfSort(s, sort) == REF(_).
  isMutableExp(s, FieldAccess(FAVar(var), x), t) :- {}
    varType == variableType(s, var),
    isMutableProperty(varType, x).