about summary refs log tree commit diff stats
path: root/subx/apps/crenshaw2-1
Commit message (Collapse)AuthorAgeFilesLines
* 4888Kartik Agaram2018-12-291-0/+0
| | | | We only can't use rm32=5 when mod=0. Totally fine when it's mod=1.
* 4883 - rudimentary memory allocatorKartik Agaram2018-12-281-0/+0
|
* 4879Kartik Agaram2018-12-281-0/+0
|
* 4865Kartik Agaram2018-12-101-0/+0
| | | | More mnemonic register usage in write-stream.
* 4864Kartik Agaram2018-12-101-0/+0
| | | | Our first buffer overflow!
* 4846Kartik Agaram2018-12-061-0/+0
| | | | | | | | | | | | | | Clean up a few things: a) Call scan-next-byte in hex.subx with the right number of args. Turns out tests continue to work fine if they never use the other args. b) Tear down a test for 'stop' in the right order. Not important since we have no EBP to restore. But can still be misleading. c) Have 'check-ints-equal' return nothing. Handy for it to not mess up EAX. I never use the result anyway, and the name also is imperative suggesting callers won't expect a return value.
* 4844Kartik Agaram2018-12-061-0/+0
|
* 4841Kartik Agaram2018-12-041-0/+0
| | | | New helper: print an error message, then a numeric byte, then abort.
* 4840Kartik Agaram2018-12-041-0/+0
| | | | New helper: printing a string to a buffered file.
* 4838Kartik Agaram2018-12-041-0/+0
| | | | Better to use EDI as a mnemonic for 'destination'.
* 4837Kartik Agaram2018-12-041-0/+0
| | | | Let's standardize to use opcode 39 rather than 3b by default.
* 4834Kartik Agaram2018-12-041-0/+0
| | | | Fix CI since 4827.
* 4833Kartik Agaram2018-12-041-0/+0
|
* 4828 - writing to buffered-fileKartik Agaram2018-12-031-0/+0
| | | | | This is likely a sub-optimal interface, but I'm trying not to agonize. The whole point of Mu is to permit radical changes at any point in time.
* 4827Kartik Agaram2018-12-031-0/+0
| | | | | | | | | I was 'returning' a phantom value from 'write' when the underlying '_write' returns nothing. In general, returning counts of bytes written is not so useful for error checking when my primitives abstract away from that. We'll come back to error signalling later.
* 4822Kartik Agaram2018-12-031-0/+0
| | | | | | | Fix CI. It's kind of a hassle (and wasteful) that I need to redefine 'main' in every single layer.
* 4821Kartik Agaram2018-12-021-0/+0
|
* 4810Kartik Agaram2018-11-301-0/+0
|
* 4775Kartik Agaram2018-11-241-0/+0
| | | | | | | Start with an exactly corresponding version to Crenshaw 2-1: single-digit numbers. The only change: we assume the number is in hex. The next version now supports multi-digit hex numbers.
* 4774Kartik Agaram2018-11-241-0/+0
| | | | Simplification.
* 4773 - done with crenshaw chapter 2-1Kartik Agaram2018-11-241-0/+0
| | | | In the process I had to fix a couple more bugs in support for disp16 instructions.
* 4768Kartik Agaram2018-11-241-0/+0
|
* 4764Kartik Agaram2018-11-231-0/+0
|
* 4763 - back to the 'trivial' crenshaw2-1 compilerKartik Agaram2018-11-231-0/+0
| | | | | This time I've ported (and test-driven) 'GetChar' and 'GetNum'. The new tests bring together our new testable interfaces for read() and exit().
* 4756Kartik Agaram2018-11-191-0/+0
| | | | | Long-standing and long-copied typo has been messing with our exit status on test failures.
* 4755 - read-byte (sometimes called getchar)Kartik Agaram2018-11-191-0/+0
|
* 4747 - subx: 'read' primitiveKartik Agaram2018-11-181-0/+0
|
* 4745Kartik Agaram2018-11-171-0/+0
|
* 4743Kartik Agaram2018-11-121-0/+0
|
* 4741Kartik Agaram2018-10-301-0/+0
| | | | Extract a helper that we'll need for 'read'.
* 4740Kartik Agaram2018-10-301-0/+0
|
* 4736Kartik Agaram2018-10-291-0/+0
| | | | | | | | | We'll use a common stream data structure for input and output streams. Having separate types makes more sense in a more high-level language, where we have type checking and where functions for handling the different types are more concise. But in machine code the sweet spot is more toward fewer types.
* 4732Kartik Agaram2018-10-281-0/+0
|
* 4729Kartik Agaram2018-10-281-0/+0
| | | | | | Start injecting all dependencies in the Crenshaw compiler app. In the process I realized the non-fake code path of 'stop' had a bug.
* 4721Kartik Agaram2018-10-241-0/+0
|
* 4713Kartik Agaram2018-10-211-0/+0
| | | | | | | | Initial sketch of a dependency-injected wrapper around the exit() syscall. I don't have the primitives yet, just a sketch of how they should work -- and a passing test for non-local jumps without support for passing the exit status to the caller.
* 4711Kartik Agaram2018-10-171-0/+0
| | | | | | | Extract a helper for appending strings to raw buffers. I'd been resisting this idea, but it actually turns out to be a pretty clean abstraction in the end.
* 4710Kartik Agaram2018-10-171-0/+0
| | | | | Start using write() instead of _write().. and we promptly find a typo when dealing with real file descriptors.
* 4707 - subx: dependency-injected write() primitiveKartik Agaram2018-10-161-0/+0
|
* 4699Kartik Agaram2018-10-141-0/+0
|
* 4697Kartik Agaram2018-10-141-0/+0
|
* 4691Kartik Agaram2018-10-131-0/+0
| | | | All tests now once again run the same natively and on VM.
* 4684Kartik Agaram2018-10-111-0/+0
| | | | | | | | | | Turns out the tests for 'trace' have been broken in native mode since the original commit (4674). Dangers of running my tests on Darwin, where I can't run them natively. The test failures didn't get flagged on CI because I'd forgotten to update the exit code of the factorial app in commit 4664. At least that's fixed in this commit.
* 4682 - subx: start testing all layers of 'library'Kartik Agaram2018-10-101-0/+0
|
* 4674Kartik Agaram2018-10-081-0/+0
| | | | subx: append to trace
* 4667Kartik Agaram2018-10-051-0/+0
| | | | | Standardize on hyphens in all names. And we'll use colons for namespacing labels in functions.
* 4664 - subx: reflect test failures in exit statusKartik Agaram2018-10-051-0/+0
|
* 4661Kartik Agaram2018-10-041-0/+0
| | | | | Make segment management a little more consistent between initial segments and add-on segments (using `mmap`).
* 4658 - subx: string_equalKartik Agaram2018-10-021-0/+0
|
* 4645Kartik Agaram2018-10-011-0/+0
|
">t*: RelationType flag*: RelationFlag Selector* = ref object # Simple selector case t*: SelectorType of stType: tag*: CAtom when defined(debug): tags: string of stId: id*: CAtom when defined(debug): ids: string of stClass: class*: CAtom when defined(debug): classs: string of stAttr: attr*: CAtom when defined(debug): attrs: string value*: string rel*: SelectorRelation of stUniversal: #TODO namespaces? discard of stPseudoClass: pseudo*: PseudoData of stPseudoElement: elem*: PseudoElem PseudoData* = object case t*: PseudoClass of pcNthChild, pcNthLastChild: anb*: CSSAnB ofsels*: SelectorList of pcIs, pcWhere, pcNot: fsels*: SelectorList of pcLang: s*: string else: discard CompoundSelector* = object ct*: CombinatorType # relation to the next entry in a ComplexSelector. sels*: seq[Selector] ComplexSelector* = seq[CompoundSelector] SelectorList* = seq[ComplexSelector] iterator items*(sels: CompoundSelector): Selector {.inline.} = for it in sels.sels: yield it func `[]`*(sels: CompoundSelector; i: int): Selector {.inline.} = return sels.sels[i] func `[]`*(sels: CompoundSelector; i: BackwardsIndex): Selector {.inline.} = return sels.sels[i] func len*(sels: CompoundSelector): int {.inline.} = return sels.sels.len proc add*(sels: var CompoundSelector; sel: Selector) {.inline.} = sels.sels.add(sel) func `$`*(cxsel: ComplexSelector): string func `$`*(sel: Selector): string = case sel.t of stType: when defined(debug): return sel.tags else: return "ATOM" & $int(sel.tag) of stId: when defined(debug): return "#" & sel.ids else: return "#ATOM" & $int(sel.id) of stAttr: let rel = case sel.rel.t of rtExists: "" of rtEquals: "=" of rtToken: "~=" of rtBeginDash: "|=" of rtStartsWith: "^=" of rtEndsWith: "$=" of rtContains: "*=" let flag = case sel.rel.flag of rfNone: "" of rfI: " i" of rfS: " s" let attrs = when defined(debug): sel.attrs else: "ATOM" & $int(sel.attr) return '[' & attrs & rel & sel.value & flag & ']' of stClass: when defined(debug): return "." & sel.classs else: return ".ATOM" & $int(sel.id) of stUniversal: return "*" of stPseudoClass: result = ':' & $sel.pseudo.t case sel.pseudo.t of pcIs, pcNot, pcWhere: result &= '(' for fsel in sel.pseudo.fsels: result &= $fsel if fsel != sel.pseudo.fsels[^1]: result &= ", " result &= ')' of pcNthChild, pcNthLastChild: result &= '(' & $sel.pseudo.anb.A & 'n' & $sel.pseudo.anb.B if sel.pseudo.ofsels.len != 0: result &= " of " for fsel in sel.pseudo.ofsels: result &= $fsel if fsel != sel.pseudo.ofsels[^1]: result &= ',' result &= ')' else: discard of stPseudoElement: return "::" & $sel.elem func `$`*(sels: CompoundSelector): string = for sel in sels: result &= $sel func `$`*(cxsel: ComplexSelector): string = for sels in cxsel: result &= $sels case sels.ct of ctDescendant: result &= ' ' of ctChild: result &= " > " of ctNextSibling: result &= " + " of ctSubsequentSibling: result &= " ~ " of ctNone: discard func `$`*(slist: SelectorList): string = var s = false for cxsel in slist: if s: result &= ", " result &= $cxsel s = true func getSpecificity*(cxsel: ComplexSelector): int func getSpecificity(sel: Selector): int = case sel.t of stId: result += 1000000 of stClass, stAttr: result += 1000 of stPseudoClass: case sel.pseudo.t of pcIs, pcNot: var best = 0 for child in sel.pseudo.fsels: let s = getSpecificity(child) if s > best: best = s result += best of pcNthChild, pcNthLastChild: if sel.pseudo.ofsels.len != 0: var best = 0 for child in sel.pseudo.ofsels: let s = getSpecificity(child) if s > best: best = s result += best result += 1000 of pcWhere: discard else: result += 1000 of stType, stPseudoElement: result += 1 of stUniversal: discard func getSpecificity*(sels: CompoundSelector): int = for sel in sels: result += getSpecificity(sel) func getSpecificity*(cxsel: ComplexSelector): int = for sels in cxsel: result += getSpecificity(sels) func pseudo*(cxsel: ComplexSelector): PseudoElem = if cxsel[^1][^1].t == stPseudoElement: return cxsel[^1][^1].elem return peNone proc consume(state: var SelectorParser): CSSComponentValue = result = state.cvals[state.at] inc state.at proc has(state: var SelectorParser; i = 0): bool = return not state.failed and state.at + i < state.cvals.len proc peek(state: var SelectorParser; i = 0): CSSComponentValue = return state.cvals[state.at + i] template fail() = state.failed = true return template get_tok(cval: CSSComponentValue): CSSToken = let c = cval if not (c of CSSToken): fail CSSToken(c) proc parseSelectorList(cvals: seq[CSSComponentValue]; factory: CAtomFactory; nested, forgiving: bool): SelectorList # Functions that may contain other selectors, functions, etc. proc parseRecursiveSelectorFunction(state: var SelectorParser; class: PseudoClass; body: seq[CSSComponentValue]; forgiving: bool): Selector = var fun = Selector( t: stPseudoClass, pseudo: PseudoData(t: class), ) fun.pseudo.fsels = parseSelectorList(body, state.factory, nested = true, forgiving) if fun.pseudo.fsels.len == 0: fail return fun proc parseNthChild(state: var SelectorParser; cssfunction: CSSFunction; data: PseudoData): Selector = var data = data var (anb, i) = parseAnB(cssfunction.value) if anb.isNone: fail data.anb = anb.get var nthchild = Selector(t: stPseudoClass, pseudo: data) while i < cssfunction.value.len and cssfunction.value[i] == cttWhitespace: inc i if i >= cssfunction.value.len: return nthchild let lasttok = get_tok cssfunction.value[i] if lasttok.t != cttIdent or not lasttok.value.equalsIgnoreCase("of"): fail inc i while i < cssfunction.value.len and cssfunction.value[i] == cttWhitespace: inc i if i == cssfunction.value.len: fail nthchild.pseudo.ofsels = cssfunction.value[i..^1] .parseSelectorList(state.factory, nested = true, forgiving = false) if nthchild.pseudo.ofsels.len == 0: fail return nthchild proc skipWhitespace(state: var SelectorParser) = while state.has() and state.peek() of CSSToken and CSSToken(state.peek()).t == cttWhitespace: inc state.at proc parseLang(cvals: seq[CSSComponentValue]): Selector = var state = SelectorParser(cvals: cvals) state.skipWhitespace() if not state.has(): fail let tok = get_tok state.consume() if tok.t != cttIdent: fail return Selector(t: stPseudoClass, pseudo: PseudoData(t: pcLang, s: tok.value)) proc parseSelectorFunction(state: var SelectorParser; cssfunction: CSSFunction): Selector = return case cssfunction.name.toLowerAscii() of "not": state.parseRecursiveSelectorFunction(pcNot, cssfunction.value, forgiving = false) of "is": state.parseRecursiveSelectorFunction(pcIs, cssfunction.value, forgiving = true) of "where": state.parseRecursiveSelectorFunction(pcWhere, cssfunction.value, forgiving = true) of "nth-child": state.parseNthChild(cssfunction, PseudoData(t: pcNthChild)) of "nth-last-child": state.parseNthChild(cssfunction, PseudoData(t: pcNthLastChild)) of "lang": parseLang(cssfunction.value) else: fail proc parsePseudoSelector(state: var SelectorParser): Selector = if not state.has(): fail let cval = state.consume() if cval of CSSToken: template add_pseudo_element(element: PseudoElem) = state.skipWhitespace() if state.nested or state.has() and state.peek() != cttComma: fail return Selector(t: stPseudoElement, elem: element) let tok = CSSToken(cval) case tok.t of cttIdent: template add_pseudo_class(class: PseudoClass) = return Selector(t: stPseudoClass, pseudo: PseudoData(t: class)) case tok.value.toLowerAscii() of "before": add_pseudo_element peBefore of "after": add_pseudo_element peAfter of "first-child": add_pseudo_class pcFirstChild of "last-child": add_pseudo_class pcLastChild of "only-child": add_pseudo_class pcOnlyChild of "hover": add_pseudo_class pcHover of "root": add_pseudo_class pcRoot of "checked": add_pseudo_class pcChecked of "focus": add_pseudo_class pcFocus of "link": add_pseudo_class pcLink of "visited": add_pseudo_class pcVisited of "target": add_pseudo_class pcTarget of "-cha-first-node": add_pseudo_class pcFirstNode of "-cha-last-node": add_pseudo_class pcLastNode else: fail of cttColon: if not state.has(): fail let tok = get_tok state.consume() if tok.t != cttIdent: fail case tok.value.toLowerAscii() of "before": add_pseudo_element peBefore of "after": add_pseudo_element peAfter else: fail else: fail elif cval of CSSFunction: return state.parseSelectorFunction(CSSFunction(cval)) else: fail proc parseComplexSelector(state: var SelectorParser): ComplexSelector proc parseAttributeSelector(state: var SelectorParser; cssblock: CSSSimpleBlock): Selector = if cssblock.token.t != cttLbracket: fail var state2 = SelectorParser(cvals: cssblock.value) state2.skipWhitespace() if not state2.has(): fail let attr = get_tok state2.consume() if attr.t != cttIdent: fail state2.skipWhitespace() if not state2.has(): return Selector( t: stAttr, attr: state.factory.toAtomLower(attr.value), rel: SelectorRelation(t: rtExists) ) let delim = get_tok state2.consume() if delim.t != cttDelim: fail let rel = case delim.cvalue of '~': rtToken of '|': rtBeginDash of '^': rtStartsWith of '$': rtEndsWith of '*': rtContains of '=': rtEquals else: fail if rel != rtEquals: let delim = get_tok state2.consume() if delim.t != cttDelim or delim.cvalue != '=': fail state2.skipWhitespace() if not state2.has(): fail let value = get_tok state2.consume() if value.t notin {cttIdent, cttString}: fail state2.skipWhitespace() var flag = rfNone if state2.has(): let delim = get_tok state2.consume() if delim.t != cttIdent: fail if delim.value.equalsIgnoreCase("i"): flag = rfI elif delim.value.equalsIgnoreCase("s"): flag = rfS return Selector( t: stAttr, attr: state.factory.toAtom(attr.value), value: value.value, rel: SelectorRelation( t: rel, flag: flag ) ) proc parseClassSelector(state: var SelectorParser): Selector = if not state.has(): fail let tok = get_tok state.consume() if tok.t != cttIdent: fail let class = state.factory.toAtomLower(tok.value) result = Selector(t: stClass, class: class) when defined(debug): result.classs = tok.value proc parseCompoundSelector(state: var SelectorParser): CompoundSelector = result = CompoundSelector() while state.has(): let cval = state.peek() if cval of CSSToken: let tok = CSSToken(cval) case tok.t of cttIdent: inc state.at let tag = state.factory.toAtomLower(tok.value) let sel = Selector(t: stType, tag: tag) when defined(debug): sel.tags = tok.value result.add(sel) of cttColon: inc state.at result.add(state.parsePseudoSelector()) of cttHash: inc state.at let id = state.factory.toAtomLower(tok.value) result.add(Selector(t: stId, id: id)) when defined(debug): result[^1].ids = tok.value of cttComma: break of cttDelim: case tok.cvalue of '.': inc state.at result.add(state.parseClassSelector()) of '*': inc state.at result.add(Selector(t: stUniversal)) of '>', '+', '~': break else: fail of cttWhitespace: # skip trailing whitespace if not state.has(1) or state.peek(1) == cttComma: inc state.at elif state.peek(1) == cttDelim: let tok = CSSToken(state.peek(1)) if tok.cvalue in {'>', '+', '~'}: inc state.at break else: fail elif cval of CSSSimpleBlock: inc state.at result.add(state.parseAttributeSelector(CSSSimpleBlock(cval))) else: fail proc parseComplexSelector(state: var SelectorParser): ComplexSelector = while true: state.skipWhitespace() let sels = state.parseCompoundSelector() result.add(sels) if sels.len == 0: fail if not state.has(): break # finish let tok = get_tok state.consume() case tok.t of cttDelim: case tok.cvalue of '>': result[^1].ct = ctChild of '+': result[^1].ct = ctNextSibling of '~': result[^1].ct = ctSubsequentSibling else: fail of cttWhitespace: result[^1].ct = ctDescendant of cttComma: break # finish else: fail if result.len == 0 or result[^1].ct != ctNone: fail proc parseSelectorList(cvals: seq[CSSComponentValue]; factory: CAtomFactory; nested, forgiving: bool): SelectorList = var state = SelectorParser( cvals: cvals, factory: factory, nested: nested ) var res: SelectorList = @[] while state.has(): let csel = state.parseComplexSelector() if state.failed: if not forgiving: return @[] state.failed = false while state.has() and state.consume() != cttComma: discard else: res.add(csel) return res proc parseSelectors*(cvals: seq[CSSComponentValue]; factory: CAtomFactory): seq[ComplexSelector] = return parseSelectorList(cvals, factory, nested = false, forgiving = false) proc parseSelectors*(ibuf: string; factory: CAtomFactory): seq[ComplexSelector] = return parseSelectors(parseComponentValues(ibuf), factory)