about summary refs log tree commit diff stats
path: root/mu_instructions
Commit message (Collapse)AuthorAgeFilesLines
* 6920Kartik Agaram2020-10-011-1/+1
|
* 6915 - a new family of Mu branch instructionsKartik Agaram2020-09-301-0/+6
| | | | | | The realization of commit 6916 means that we should be using jump-if-addr* after comparing floats. Which is super ugly. Let's create aliases to them called jump-if-float*.
* 6908 - compiling all floating-point operationsKartik Agaram2020-09-301-2/+2
| | | | | We don't yet support emulating these instructions in `bootstrap`. But generated binaries containing them run natively just fine.
* 6896Kartik Agaram2020-09-281-0/+77
| | | | Readme-driven development for Mu's floating-point operations.
* 6894Kartik Agaram2020-09-281-0/+9
|
* 6893Kartik Agaram2020-09-281-6/+6
|
* 6698Kartik Agaram2020-08-011-1/+1
|
* 6697Kartik Agaram2020-08-011-13/+9
|
* 6657Kartik Agaram2020-07-161-16/+0
|
* 6648 - bit-shift instructions in MuKartik Agaram2020-07-141-0/+7
| | | | I'm not happy with the names.
* 6645 - heap allocations in MuKartik Agaram2020-07-131-0/+8
| | | | | | | | - allocate var - populate var, n Both rely on the type of `var` to compute the size of the allocation. No need to repeat the name of the type like in C, C++ or Java.
* 6516 - operations on bytesKartik Agaram2020-06-131-0/+4
| | | | | | Byte-oriented addressing is only supported in a couple of instructions in SubX. As a result, variables of type 'byte' can't live on the stack, or in registers 'esi' and 'edi'.
* 6468Kartik Agaram2020-06-051-2/+2
|
* 6465Kartik Agaram2020-06-041-0/+1
|
* 6408Kartik Agaram2020-05-271-1/+2
|
* 6405Kartik Agaram2020-05-251-1/+1
|
* 6392 - 'length' instruction done in all complexityKartik Agaram2020-05-241-1/+1
|
* 6390 - return `length` in elementsKartik Agaram2020-05-241-1/+25
|
* 6389Kartik Agaram2020-05-241-9/+14
|
* 6173Kartik Agaram2020-03-271-5/+12
|
* 6170Kartik Agaram2020-03-251-3/+3
|
* 6169Kartik Agaram2020-03-251-1/+1
|
* 6164Kartik Agaram2020-03-241-2/+2
|
* 6160 - plan for safe heap accessKartik Agaram2020-03-211-2/+31
| | | | | | | | | Based on apps/handle.subx (commit 4894), but we're able to simplify it further now that we know more about the situation we find ourselves in. 6 instructions, zero pushes or pops. Before I can start building this, I need to reorganize my use of handles. They're going to be fat pointers so we can't store them in registers anymore.
* 6159Kartik Agaram2020-03-211-218/+165
|
* 6158 - standardize opcode namesKartik Agaram2020-03-211-29/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | At the lowest level, SubX without syntax sugar uses names without prepositions. For example, 01 and 03 are both called 'add', irrespective of source and destination operand. Horizontal space is at a premium, and we rely on the comments at the end of each line to fully describe what is happening. Above that, however, we standardize on a slightly different naming convention across: a) SubX with syntax sugar, b) Mu, and c) the SubX code that the Mu compiler emits. Conventions, in brief: - by default, the source is on the left and destination on the right. e.g. add %eax, 1/r32/ecx ("add eax to ecx") - prepositions reverse the direction. e.g. add-to %eax, 1/r32/ecx ("add ecx to eax") subtract-from %eax, 1/r32/ecx ("subtract ecx from eax") - by default, comparisons are left to right while 'compare<-' reverses. Before, I was sometimes swapping args to make the operation more obvious, but that would complicate the code-generation of the Mu compiler, and it's nice to be able to read the output of the compiler just like hand-written code. One place where SubX differs from Mu: copy opcodes are called '<-' and '->'. Hopefully that fits with the spirit of Mu rather than the letter of the 'copy' and 'copy-to' instructions.
* 6145 - 'address' operatorKartik Agaram2020-03-141-0/+5
| | | | | This could be a can of worms, but I think I have a set of checks that will keep use of addresses type-safe.
* 6131 - operating on arrays on the stackKartik Agaram2020-03-121-1/+5
|
* 6129Kartik Agaram2020-03-111-1/+3
|
* 6097Kartik Agaram2020-03-071-2/+0
| | | | | | I thought I needed to support compute-offset with literal index, but in that case might as well just use an index literal directly. The 'index' instruction with literals already supports non-power-of-2 sizes.
* 6094 - new 'compute-offset' instructionKartik Agaram2020-03-071-3/+11
| | | | | | | | | | | | | | | | | | | | | | | If indexing into a type with power-of-2-sized elements we can access them in one instruction: x/reg1: (addr int) <- index A/reg2: (addr array int), idx/reg3: int This translates to a single instruction because x86 instructions support an addressing mode with left-shifts. For non-powers-of-2, however, we need a multiply. To keep things type-safe, it is performed like this: x/reg1: (offset T) <- compute-offset A: (addr array T), idx: int y/reg2: (addr T) <- index A, x An offset is just an int that is guaranteed to be a multiple of size-of(T). Offsets can only be used in index instructions, and the types will eventually be required to line up. In the process, I have to expand Input-size because mu.subx is growing big.
* 6060Kartik Agaram2020-02-271-11/+11
|
* 6059Kartik Agaram2020-02-271-0/+8
|
* 6041 - array indexing starting to workKartik Agaram2020-02-211-0/+10
| | | | | | | | | | | | | And we're using it now in factorial.mu! In the process I had to fix a couple of bugs in pointer dereferencing. There are still some limitations: a) Indexing by a literal doesn't work yet. b) Only arrays of ints supported so far. Looking ahead, I'm not sure how I can support indexing arrays by non-literals (variables in registers) unless the element size is a power of 2.
* 6039Kartik Agaram2020-02-211-0/+18
|
* 6019 - finish supporting all branch primitivesKartik Agaram2020-02-181-2/+2
| | | | | | | | I'd been thinking I didn't need unconditional `break` instructions, but I just realized that non-local unconditional breaks have a use. Stop over-thinking this, just support everything. The code is quite duplicated.
* 5968Kartik Agaram2020-02-011-24/+22
|
* 5967Kartik Agaram2020-02-011-0/+6
|
* 5966 - document all supported Mu instructionsKartik Agaram2020-01-311-0/+186
tch.nim?id=66b9574b165be62e76c7397cf0eaa8d229d42675'>66b9574b ^
fbdb7fc7 ^
c69a8ab7 ^
66b9574b ^

24fc8e94 ^




66b9574b ^

8bc1392c ^
66b9574b ^
fbdb7fc7 ^
66b9574b ^
fbdb7fc7 ^
66b9574b ^
a1c62fc9 ^
66b9574b ^
4a897f27 ^
66b9574b ^
d4d45f41 ^
72e171f6 ^
66b9574b ^

dd9cb39c ^


85796198 ^
66b9574b ^
168bd542 ^
66b9574b ^
fc730139 ^
66b9574b ^
fc730139 ^
66b9574b ^
fc730139 ^
66b9574b ^
dd9cb39c ^
66b9574b ^
2a94a270 ^
66b9574b ^
fc730139 ^
167dd672 ^
66b9574b ^

167dd672 ^




66b9574b ^

167dd672 ^






66b9574b ^
af3dbce8 ^
66b9574b ^
167dd672 ^





66b9574b ^
167dd672 ^


66b9574b ^
167dd672 ^









2b26bfdc ^

66b9574b ^
167dd672 ^















dd9cb39c ^


66b9574b ^

167dd672 ^
dd9cb39c ^


167dd672 ^
85796198 ^
66b9574b ^
3cc7f9d2 ^
51d83224 ^
252174ba ^

51d83224 ^
252174ba ^
66b9574b ^
3cc7f9d2 ^
51d83224 ^
252174ba ^


51d83224 ^
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
                  

                   
 
                    

                         
                 
               
                   

                 
 

                                                              
                

                                          
                     



                                                                  

                                 

                                                             


                                                 

                                                          
                                 
                     


                                                                

                                                 


                                                                

                                 



                                                      

                                 



                                                    

                                 

                                             


                                           
                                          
 

                                                                            
 

                                                                         

                                         


                 

                                                                         


                                 
                   






                                                                   
                     



                                                           





                                                       
                                  
                                    







                                                    

                                                         

                


                                                           





                                                       
                                  
                                        

                                           
                        




                                                    

                                                         
             
                

                                                                   




                                             

                                                                 
                                      
           
                                                            
                   
                                                        
            
                                                
            
                                                                    
               
                
 

                                                                   


                                  
            
            
                                    
             
                                      
          
                            
            
                                        
                   
                                                   
                     
               
                 
               
 

                                                                           




                                             

                                                           






                                    
              
                                           
                    





                                         
               


                                             
                     









                                                   

                                               
                           















                                                   


                                                                               

                                                                            
                              


         
                                                  
 
                                                            
                                                          
                               

                                         
                                                                               
 
                                                    
                                                          
                               


                                         
                                                                      
import std/options
import std/strutils
import std/tables

import css/cssparser
import css/selectorparser
import css/stylednode
import html/catom
import html/dom
import utils/twtstr

import chame/tags

#TODO rfNone should match insensitively for certain properties
func attrSelectorMatches(elem: Element; sel: Selector): bool =
  case sel.rel.t
  of rtExists: return elem.attrb(sel.attr)
  of rtEquals:
    case sel.rel.flag
    of rfNone: return elem.attr(sel.attr) == sel.value
    of rfI: return elem.attr(sel.attr).equalsIgnoreCase(sel.value)
    of rfS: return elem.attr(sel.attr) == sel.value
  of rtToken:
    let val = elem.attr(sel.attr)
    case sel.rel.flag
    of rfNone: return sel.value in val.split(AsciiWhitespace)
    of rfI:
      let val = val.toLowerAscii()
      let selval = sel.value.toLowerAscii()
      return selval in val.split(AsciiWhitespace)
    of rfS: return sel.value in val.split(AsciiWhitespace)
  of rtBeginDash:
    let val = elem.attr(sel.attr)
    case sel.rel.flag
    of rfNone:
      return val == sel.value or sel.value.startsWith(val & '-')
    of rfI:
      return val.equalsIgnoreCase(sel.value) or
        sel.value.startsWithIgnoreCase(val & '-')
    of rfS:
      return val == sel.value or sel.value.startsWith(val & '-')
  of rtStartsWith:
    let val = elem.attr(sel.attr)
    case sel.rel.flag
    of rfNone: return val.startsWith(sel.value)
    of rfI: return val.startsWithIgnoreCase(sel.value)
    of rfS: return val.startsWith(sel.value)
  of rtEndsWith:
    let val = elem.attr(sel.attr)
    case sel.rel.flag
    of rfNone: return val.endsWith(sel.value)
    of rfI: return val.endsWithIgnoreCase(sel.value)
    of rfS: return val.endsWith(sel.value)
  of rtContains:
    let val = elem.attr(sel.attr)
    case sel.rel.flag
    of rfNone: return val.contains(sel.value)
    of rfI:
      let val = val.toLowerAscii()
      let selval = sel.value.toLowerAscii()
      return val.contains(selval)
    of rfS: return val.contains(sel.value)

func selectorsMatch*[T: Element|StyledNode](elem: T; cxsel: ComplexSelector;
  felem: T = nil): bool

func selectorsMatch*[T: Element|StyledNode](elem: T; slist: SelectorList;
    felem: T = nil): bool =
  for cxsel in slist:
    if elem.selectorsMatch(cxsel, felem):
      return true
  return false

func pseudoSelectorMatches[T: Element|StyledNode](elem: T; sel: Selector;
    felem: T): bool =
  let selem = elem
  when elem is StyledNode:
    let elem = Element(elem.node)
  case sel.pseudo.t
  of pcFirstChild: return elem.parentNode.firstElementChild == elem
  of pcLastChild: return elem.parentNode.lastElementChild == elem
  of pcOnlyChild:
    return elem.parentNode.firstElementChild == elem and
      elem.parentNode.lastElementChild == elem
  of pcHover:
    when selem is StyledNode: felem.addDependency(selem, dtHover)
    return elem.hover
  of pcRoot: return elem == elem.document.html
  of pcNthChild:
    if sel.pseudo.ofsels.len != 0 and
        not selem.selectorsMatch(sel.pseudo.ofsels, felem):
      return false
    let A = sel.pseudo.anb.A # step
    let B = sel.pseudo.anb.B # start
    var i = 1
    let parent = when selem is StyledNode: selem.parent
    else: selem.parentNode
    if parent == nil: return false
    for child in parent.elementList:
      when selem is StyledNode:
        if not child.isDomElement: continue
      if child == selem:
        if A == 0:
          return i == B
        if A < 0:
          return (i - B) <= 0 and (i - B) mod A == 0
        return (i - B) >= 0 and (i - B) mod A == 0
      if sel.pseudo.ofsels.len == 0 or
          child.selectorsMatch(sel.pseudo.ofsels, felem):
        inc i
    return false
  of pcNthLastChild:
    if sel.pseudo.ofsels.len == 0 and
        not selem.selectorsMatch(sel.pseudo.ofsels, felem):
      return false
    let A = sel.pseudo.anb.A # step
    let B = sel.pseudo.anb.B # start
    var i = 1
    let parent = when selem is StyledNode: selem.parent
    else: selem.parentNode
    if parent == nil: return false
    for child in parent.elementList_rev:
      when selem is StyledNode:
        if not child.isDomElement: continue
      if child == selem:
        if A == 0:
          return i == B
        if A < 0:
          return (i - B) <= 0 and (i - B) mod A == 0
        return (i - B) >= 0 and (i - B) mod A == 0
      if sel.pseudo.ofsels.len != 0 or
          child.selectorsMatch(sel.pseudo.ofsels, felem):
        inc i
    return false
  of pcChecked:
    when selem is StyledNode: felem.addDependency(selem, dtChecked)
    if elem.tagType == TAG_INPUT:
      return HTMLInputElement(elem).checked
    elif elem.tagType == TAG_OPTION:
      return HTMLOptionElement(elem).selected
    return false
  of pcFocus:
    when selem is StyledNode: felem.addDependency(selem, dtFocus)
    return elem.document.focus == elem
  of pcNot:
    return not selem.selectorsMatch(sel.pseudo.fsels, felem)
  of pcIs, pcWhere:
    return selem.selectorsMatch(sel.pseudo.fsels, felem)
  of pcLang:
    return sel.pseudo.s == "en" #TODO languages?
  of pcLink:
    return elem.tagType in {TAG_A, TAG_AREA} and elem.attrb(satHref)
  of pcVisited:
    return false

func selectorMatches[T: Element|StyledNode](elem: T; sel: Selector;
    felem: T = nil): bool =
  let selem = elem
  when elem is StyledNode:
    let elem = Element(selem.node)
  case sel.t
  of stType:
    return elem.localName == sel.tag
  of stClass:
    return sel.class in elem.classList
  of stId:
    return sel.id == elem.id
  of stAttr:
    return elem.attrSelectorMatches(sel)
  of stPseudoClass:
    return pseudoSelectorMatches(selem, sel, felem)
  of stPseudoElement:
    return true
  of stUniversal:
    return true

func selectorsMatch[T: Element|StyledNode](elem: T; sels: CompoundSelector;
    felem: T): bool =
  for sel in sels:
    if not selectorMatches(elem, sel, felem):
      return false
  return true

func complexSelectorMatches[T: Element|StyledNode](elem: T;
    cxsel: ComplexSelector; felem: T = nil): bool =
  var e = elem
  for i in countdown(cxsel.high, 0):
    let sels = cxsel[i]
    if e == nil:
      return false
    var match = false
    case sels.ct
    of ctNone:
      match = e.selectorsMatch(sels, felem)
    of ctDescendant:
      e = e.parentElement
      while e != nil:
        if e.selectorsMatch(sels, felem):
          match = true
          break
        e = e.parentElement
    of ctChild:
      e = e.parentElement
      if e != nil:
        match = e.selectorsMatch(sels, felem)
    of ctNextSibling:
      if e.parentElement == nil: return false
      var found = false
      for child in e.parentElement.elementList_rev:
        when elem is StyledNode:
          if not child.isDomElement: continue
        if e == child:
          found = true
          continue
        if found:
          e = child
          match = e.selectorsMatch(sels, felem)
          break
    of ctSubsequentSibling:
      var found = false
      if e.parentElement == nil: return false
      for child in e.parentElement.elementList_rev:
        when elem is StyledNode:
          if not child.isDomElement: continue
        if child == elem:
          found = true
          continue
        if not found: continue
        if child.selectorsMatch(sels, felem):
          e = child
          match = true
          break
    if not match:
      return false
  return true

# WARNING for StyledNode, this has the side effect of modifying depends.
#TODO make that an explicit flag or something, also get rid of the Element case
func selectorsMatch*[T: Element|StyledNode](elem: T; cxsel: ComplexSelector;
    felem: T = nil): bool =
  var felem = if felem != nil:
    felem
  else:
    elem
  return elem.complexSelectorMatches(cxsel, felem)

proc querySelectorAll(node: Node; q: string): seq[Element] =
  let selectors = parseSelectors(q, node.document.factory)
  for element in node.elements:
    if element.selectorsMatch(selectors):
      result.add(element)
doqsa = (proc(node: Node, q: string): seq[Element] = querySelectorAll(node, q))

proc querySelector(node: Node; q: string): Element =
  let selectors = parseSelectors(q, node.document.factory)
  for element in node.elements:
    if element.selectorsMatch(selectors):
      return element
  return nil
doqs = (proc(node: Node, q: string): Element = querySelector(node, q))