about summary refs log tree commit diff stats
path: root/src/css/cssparser.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-08-10 15:21:12 +0200
committerbptato <nincsnevem662@gmail.com>2021-08-10 15:21:12 +0200
commit6cea57b35e4e749de531faf6502237c1cf7ed022 (patch)
tree245797fffe7e9e07755772796add914f5d61fae0 /src/css/cssparser.nim
parenta5f7da0428fdb74d9691cd6d589047478f422898 (diff)
downloadchawan-6cea57b35e4e749de531faf6502237c1cf7ed022.tar.gz
Rename cssparser.nim
Diffstat (limited to 'src/css/cssparser.nim')
-rw-r--r--src/css/cssparser.nim818
1 files changed, 0 insertions, 818 deletions
diff --git a/src/css/cssparser.nim b/src/css/cssparser.nim
deleted file mode 100644
index fac1bce8..00000000
--- a/src/css/cssparser.nim
+++ /dev/null
@@ -1,818 +0,0 @@
-# CSS tokenizer and parser. It kinda works, though certain less specific
-# details of the specification might have been implemented incorrectly.
-
-import unicode
-import streams
-import math
-import options
-import sugar
-
-import utils/twtstr
-import types/enums
-
-type
-  CSSTokenizerState = object
-    at: int
-    stream: Stream
-    buf: seq[Rune]
-
-  CSSParseState = object
-    tokens: seq[CSSParsedItem]
-    at: int
-    top_level: bool
-
-  tflaga = enum
-    TFLAGA_UNRESTRICTED, TFLAGA_ID
-  tflagb = enum
-    TFLAGB_INTEGER, TFLAGB_NUMBER
-
-  CSSParsedItem* = ref object of RootObj
-  CSSComponentValue* = ref object of CSSParsedItem
-
-  CSSToken* = ref object of CSSComponentValue
-    case tokenType*: CSSTokenType
-    of CSS_IDENT_TOKEN, CSS_FUNCTION_TOKEN, CSS_AT_KEYWORD_TOKEN,
-       CSS_HASH_TOKEN, CSS_STRING_TOKEN, CSS_URL_TOKEN:
-      value*: seq[Rune]
-      tflaga*: tflaga
-    of CSS_DELIM_TOKEN:
-      rvalue*: Rune
-    of CSS_NUMBER_TOKEN, CSS_PERCENTAGE_TOKEN, CSS_DIMENSION_TOKEN:
-      nvalue*: float64
-      tflagb*: tflagb
-      unit*: seq[Rune]
-    else: discard
-
-  CSSRule* = ref object of CSSParsedItem
-    prelude*: seq[CSSComponentValue]
-    oblock*: CSSSimpleBlock
-
-  CSSAtRule* = ref object of CSSRule
-    name*: seq[Rune]
-
-  CSSQualifiedRule* = ref object of CSSRule
-
-  CSSDeclaration* = ref object of CSSComponentValue
-    name*: seq[Rune]
-    value*: seq[CSSComponentValue]
-    important*: bool
-
-  CSSFunction* = ref object of CSSComponentValue
-    name*: seq[Rune]
-    value*: seq[CSSComponentValue]
-
-  CSSSimpleBlock* = ref object of CSSComponentValue
-    token*: CSSToken
-    value*: seq[CSSComponentValue]
-
-  CSSStylesheet* = object
-    value*: seq[CSSRule]
-
-  SyntaxError = object of ValueError
-
-func `==`*(a: CSSParsedItem, b: CSSTokenType): bool =
-  return a of CSSToken and CSSToken(a).tokenType == b
-
-func toNumber(s: seq[Rune]): float64 =
-  var sign = 1
-  var t = 1
-  var d = 0
-  var integer: float64 = 0
-  var f: float64 = 0
-  var e: float64 = 0
-
-  var i = 0
-  if i < s.len and s[i] == Rune('-'):
-    sign = -1
-    inc i
-  elif i < s.len and s[i] == Rune('+'):
-    inc i
-
-  while i < s.len and isDigitAscii(s[i]):
-    integer *= 10
-    integer += float64(decValue(s[i]))
-    inc i
-
-  if i < s.len and s[i] == Rune('.'):
-    inc i
-    while i < s.len and isDigitAscii(s[i]):
-      f *= 10
-      f += float64(decValue(s[i]))
-      inc i
-      inc d
-
-  if i < s.len and (s[i] == Rune('e') or s[i] == Rune('E')):
-    inc i
-    if i < s.len and s[i] == Rune('-'):
-      t = -1
-      inc i
-    elif i < s.len and s[i] == Rune('+'):
-      inc i
-
-    while i < s.len and isDigitAscii(s[i]):
-      e *= 10
-      e += float64(decValue(s[i]))
-      inc i
-
-  return float64(sign) * (integer + f * pow(10, float64(-d))) * pow(10, (float64(t) * e))
-
-func isNameStartCodePoint*(r: Rune): bool =
-  return not isAscii(r) or r == Rune('_') or isAlphaAscii(r)
-
-func isNameCodePoint*(r: Rune): bool =
-  return isNameStartCodePoint(r) or isDigitAscii(r) or r == Rune('-')
-
-proc consume(state: var CSSTokenizerState): Rune =
-  result = state.buf[state.at]
-  inc state.at
-
-proc reconsume(state: var CSSTokenizerState) =
-  dec state.at
-
-func peek(state: CSSTokenizerState, i: int): Rune =
-  return state.buf[state.at + i]
-
-proc has(state: var CSSTokenizerState, i: int): bool =
-  if state.at + i >= state.buf.len and not state.stream.atEnd():
-    state.buf &= state.stream.readLine().toRunes() & Rune('\n')
-  return state.at + i < state.buf.len
-
-func curr(state: CSSTokenizerState): Rune =
-  return state.buf[state.at]
-
-proc isValidEscape*(state: var CSSTokenizerState): bool =
-  return state.has(1) and state.curr() == Rune('\\') and state.peek(1) != Rune('\n')
-
-proc has(state: var CSSTokenizerState): bool =
-  if state.at >= state.buf.len and not state.stream.atEnd():
-    state.buf &= state.stream.readLine().toRunes() & Rune('\n')
-  return state.at < state.buf.len
-
-proc startsWithIdentifier*(state: var CSSTokenizerState): bool =
-  if not state.has():
-    return false
-
-  if isNameStartCodePoint(state.curr()):
-    return true
-  if state.curr() == Rune('-'):
-    if state.has(1) and state.peek(1).isNameStartCodePoint():
-      return true
-    if state.isValidEscape():
-      return true
-    return false
-  elif state.curr() == Rune('\\'):
-    return state.isValidEscape()
-
-  return false
-
-proc startsWithNumber*(state: var CSSTokenizerState): bool =
-  if state.has():
-    case state.curr()
-    of Rune('+'), Rune('-'):
-      if state.has(1):
-        if isDigitAscii(state.peek(1)):
-          return true
-        elif state.peek(1) == Rune('.'):
-          if state.has(2) and isDigitAscii(state.peek(2)):
-            return true
-    of Rune('.'):
-      if isDigitAscii(state.peek(1)):
-        return true
-    elif isDigitAscii(state.curr()):
-      return true
-    else:
-      return false
-  return false
-
-proc consumeEscape(state: var CSSTokenizerState): Rune =
-  let r = state.consume()
-  var num = hexValue(r)
-  if num != -1:
-    var i = 0
-    while state.has() and i <= 5:
-      let r = state.consume()
-      if hexValue(r) == -1:
-        state.reconsume()
-        break
-      num *= 0x10
-      num += hexValue(r)
-      inc i
-    if num == 0 or num > 0x10FFFF or num in {0xD800..0xDFFF}:
-      return Rune(0xFFFD)
-    else:
-      return Rune(num)
-  else:
-    return r
-
-proc consumeString(state: var CSSTokenizerState): CSSToken =
-  var s: seq[Rune]
-  state.reconsume()
-  let ending = state.consume()
-
-  while state.has():
-    let r = state.consume()
-    case r
-    of Rune('\n'):
-      return CSSToken(tokenType: CSS_BAD_STRING_TOKEN)
-    of Rune('\\'):
-      s &= consumeEscape(state)
-    elif r == ending:
-      break
-    else:
-      s &= r
-  return CSSToken(tokenType: CSS_STRING_TOKEN, value: s)
-
-proc consumeName(state: var CSSTokenizerState): seq[Rune] =
-  while state.has():
-    let r = state.consume()
-    if state.isValidEscape():
-      result &= state.consumeEscape()
-    elif isNameCodePoint(r):
-      result &= r
-    else:
-      state.reconsume()
-      return result
-
-proc consumeNumberSign(state: var CSSTokenizerState): CSSToken =
-  if state.has():
-    let r = state.consume()
-    if isNameCodePoint(r) or state.isValidEscape():
-      result = CSSToken(tokenType: CSS_HASH_TOKEN)
-      if state.startsWithIdentifier():
-        result.tflaga = TFLAGA_ID
-      
-      state.reconsume()
-      result.value = consumeName(state)
-  else:
-    let r = state.consume()
-    result = CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-
-proc consumeNumber(state: var CSSTokenizerState): tuple[t: tflagb, val: float64] =
-  var t = TFLAGB_INTEGER
-  var repr: seq[Rune]
-  if state.has():
-    if state.curr() == Rune('+') or state.curr() == Rune('-'):
-      repr &= state.consume()
-
-  while state.has() and isDigitAscii(state.curr()):
-    repr &= state.consume()
-
-  if state.has(1):
-    if state.curr() == Rune('.') and isDigitAscii(state.peek(1)):
-      repr &= state.consume()
-      repr &= state.consume()
-      t = TFLAGB_NUMBER
-      while state.has() and isDigitAscii(state.curr()):
-        repr &= state.consume()
-
-  if state.has(1):
-    if state.curr() == Rune('E') or state.curr() == Rune('e'):
-      var j = 2
-      if state.peek(1) == Rune('-') or state.peek(1) == Rune('+'):
-        inc j
-      if state.has(j) and isDigitAscii(state.peek(j)):
-        while j > 0:
-          repr &= state.consume()
-          dec j
-
-        while state.has() and isDigitAscii(state.curr()):
-          repr &= state.consume()
-
-  let val = toNumber(repr)
-  return (t, val)
-
-proc consumeNumericToken(state: var CSSTokenizerState): CSSToken =
-  let num = state.consumeNumber()
-  if state.startsWithIdentifier():
-    result = CSSToken(tokenType: CSS_DIMENSION_TOKEN, nvalue: num.val, tflagb: num.t)
-    result.unit = state.consumeName()
-  elif state.has() and state.curr() == Rune('%'):
-    discard state.consume()
-    result = CSSToken(tokenType: CSS_PERCENTAGE_TOKEN, nvalue: num.val)
-  else:
-    result = CSSToken(tokenType: CSS_NUMBER_TOKEN, nvalue: num.val, tflagb: num.t)
-
-proc consumeBadURL(state: var CSSTokenizerState) =
-  while state.has(1):
-    let r = state.consume()
-    case r
-    of Rune(')'):
-      return
-    elif state.isValidEscape():
-      discard state.consumeEscape()
-    else: discard
-
-proc consumeURL(state: var CSSTokenizerState): CSSToken =
-  result = CSSToken(tokenType: CSS_URL_TOKEN)
-  while state.has(1) and state.peek(1).isWhitespace():
-    discard state.consume()
-
-  while state.has(1):
-    let r = state.consume()
-    case r
-    of Rune(')'):
-      return result
-    of Rune('"'), Rune('\''), Rune('('):
-      state.consumeBadURL()
-      return CSSToken(tokenType: CSS_BAD_URL_TOKEN)
-    of Rune('\\'):
-      state.reconsume()
-      if state.isValidEscape():
-        result.value &= state.consumeEscape()
-      else:
-        state.consumeBadURL()
-        return CSSToken(tokenType: CSS_BAD_URL_TOKEN)
-    elif r.isWhitespace():
-      while state.has(1) and state.peek(1).isWhitespace():
-        discard state.consume()
-    else:
-      result.value &= r
-
-proc consumeIdentLikeToken(state: var CSSTokenizerState): CSSToken =
-  let s = state.consumeName()
-  if s.toAsciiLower() == "url" and state.has() and state.curr() == Rune('('):
-    discard state.consume()
-    while state.has(1) and state.curr().isWhitespace() and state.peek(1).isWhitespace():
-      discard state.consume()
-    if state.curr() == Rune('\'') or state.curr() == Rune('"') or state.curr().isWhitespace():
-      return CSSToken(tokenType: CSS_FUNCTION_TOKEN, value: s)
-    else:
-      return state.consumeURL()
-  elif state.has() and state.curr() == Rune('('):
-    discard state.consume()
-    return CSSToken(tokenType: CSS_FUNCTION_TOKEN, value: s)
-
-  return CSSToken(tokenType: CSS_IDENT_TOKEN, value: s)
-
-proc consumeComments(state: var CSSTokenizerState) =
-  if state.has(2) and state.peek(1) == Rune('/') and state.peek(2) == Rune('*'):
-    discard state.consume()
-    discard state.consume()
-    while state.has(2) and not (state.peek(1) == Rune('*') and state.peek(2) == Rune('/')):
-      discard state.consume()
-
-    if state.has(2):
-      discard state.consume()
-    if state.has(1):
-      discard state.consume()
-
-proc consumeToken(state: var CSSTokenizerState): CSSToken =
-  state.consumeComments()
-  let r = state.consume()
-  case r
-  of Rune('\n'), Rune('\t'), Rune(' '), Rune('\f'), Rune('\r'):
-    while state.has() and state.curr().isWhitespace():
-      discard state.consume()
-    return CSSToken(tokenType: CSS_WHITESPACE_TOKEN)
-  of Rune('"'), Rune('\''):
-    return consumeString(state)
-  of Rune('#'):
-    return consumeNumberSign(state)
-  of Rune('('):
-    return CSSToken(tokenType: CSS_LPAREN_TOKEN)
-  of Rune(')'):
-    return CSSToken(tokenType: CSS_RPAREN_TOKEN)
-  of Rune('['):
-    return CSSToken(tokenType: CSS_LBRACKET_TOKEN)
-  of Rune(']'):
-    return CSSToken(tokenType: CSS_RBRACKET_TOKEN)
-  of Rune('{'):
-    return CSSToken(tokenType: CSS_LBRACE_TOKEN)
-  of Rune('}'):
-    return CSSToken(tokenType: CSS_RBRACE_TOKEN)
-  of Rune(','):
-    return CSSToken(tokenType: CSS_COMMA_TOKEN)
-  of Rune(':'):
-    return CSSToken(tokenType: CSS_COLON_TOKEN)
-  of Rune(';'):
-    return CSSToken(tokenType: CSS_SEMICOLON_TOKEN)
-  of Rune('+'):
-    if state.startsWithNumber():
-      state.reconsume()
-      return state.consumeNumericToken()
-    else:
-      return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-  of Rune('-'):
-    if state.startsWithNumber():
-      state.reconsume()
-      return state.consumeNumericToken()
-    else:
-      if state.has(2) and state.peek(1) == Rune('-') and state.peek(2) == Rune('>'):
-        discard state.consume()
-        discard state.consume()
-        return CSSToken(tokenType: CSS_CDC_TOKEN)
-      elif state.startsWithIdentifier():
-        state.reconsume()
-        result = state.consumeIdentLikeToken()
-        eprint result.value
-      else:
-        return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-  of Rune('.'):
-    if state.startsWithNumber():
-      state.reconsume()
-      return state.consumeNumericToken()
-    else:
-      return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-  of Rune('<'):
-    if state.has(3) and state.peek(1) == Rune('!') and state.peek(2) == Rune('-') and state.peek(3) == Rune('-'):
-      discard state.consume()
-      discard state.consume()
-      discard state.consume()
-      return CSSToken(tokenType: CSS_CDO_TOKEN)
-    else:
-      return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-  of Rune('@'):
-    if state.startsWithIdentifier():
-      let name = state.consumeName()
-      return CSSToken(tokenType: CSS_AT_KEYWORD_TOKEN, value: name)
-    else:
-      return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-  elif isDigitAscii(r):
-    state.reconsume()
-    return state.consumeNumericToken()
-  elif isNameStartCodePoint(r):
-    state.reconsume()
-    return state.consumeIdentLikeToken()
-  else:
-    return CSSToken(tokenType: CSS_DELIM_TOKEN, rvalue: r)
-
-proc tokenizeCSS*(inputStream: Stream): seq[CSSParsedItem] =
-  var state: CSSTokenizerState
-  state.stream = inputStream
-  state.buf = state.stream.readLine().toRunes()
-  while state.has():
-    result.add(state.consumeToken())
-
-  inputStream.close()
-
-proc consume(state: var CSSParseState): CSSParsedItem =
-  result = state.tokens[state.at]
-  inc state.at
-
-proc reconsume(state: var CSSParseState) =
-  dec state.at
-
-func has(state: CSSParseState, i: int): bool =
-  return state.at + i < state.tokens.len
-
-func curr(state: CSSParseState): CSSParsedItem =
-  return state.tokens[state.at]
-
-func has(state: CSSParseState): bool =
-  return state.at < state.tokens.len
-
-proc consumeComponentValue(state: var CSSParseState): CSSComponentValue
-
-proc consumeSimpleBlock(state: var CSSParseState): CSSSimpleBlock =
-  state.reconsume()
-  let t = CSSToken(state.consume())
-  var ending: CSSTokenType
-  case t.tokenType
-  of CSS_LBRACE_TOKEN: ending = CSS_RBRACE_TOKEN
-  of CSS_LPAREN_TOKEN: ending = CSS_RPAREN_TOKEN
-  of CSS_LBRACKET_TOKEN: ending = CSS_RBRACKET_TOKEN
-  else: raise newException(Exception, "Parse error!")
-  
-  result = CSSSimpleBlock(token: t)
-  while state.at < state.tokens.len:
-    let t = state.consume()
-    if t == ending:
-      return result
-    else:
-      if t == CSS_LBRACE_TOKEN or t == CSS_LBRACKET_TOKEN or t == CSS_LPAREN_TOKEN:
-        result.value.add(state.consumeSimpleBlock())
-      else:
-        state.reconsume()
-        result.value.add(state.consumeComponentValue())
-  return result
-
-proc consumeFunction(state: var CSSParseState): CSSFunction =
-  let t = (CSSToken)state.consume()
-  result = CSSFunction(name: t.value)
-  while state.at < state.tokens.len:
-    let t = state.consume()
-    if t == CSS_RPAREN_TOKEN:
-      return result
-    else:
-      state.reconsume()
-      result.value.add(state.consumeComponentValue())
-
-proc consumeComponentValue(state: var CSSParseState): CSSComponentValue =
-  let t = state.consume()
-  if t == CSS_LBRACE_TOKEN or t == CSS_LBRACKET_TOKEN or t == CSS_LPAREN_TOKEN:
-    return state.consumeSimpleBlock()
-  elif t == CSS_FUNCTION_TOKEN:
-    state.reconsume()
-    return state.consumeFunction()
-  return CSSComponentValue(t)
-
-proc consumeQualifiedRule(state: var CSSParseState): Option[CSSQualifiedRule] =
-  var r = CSSQualifiedRule()
-  while state.has():
-    let t = state.consume()
-    if t of CSSSimpleBlock:
-      r.oblock = state.consumeSimpleBlock()
-      return some(r)
-    elif t == CSS_LBRACE_TOKEN:
-      r.oblock = state.consumeSimpleBlock()
-      return some(r)
-    else:
-      state.reconsume()
-      r.prelude.add(state.consumeComponentValue())
-  return none(CSSQualifiedRule)
-
-
-proc consumeAtRule(state: var CSSParseState): CSSAtRule =
-  let t = CSSToken(state.consume())
-  result = CSSAtRule(name: t.value)
-
-  while state.at < state.tokens.len:
-    let t = state.consume()
-    if t of CSSSimpleBlock:
-      result.oblock = state.consumeSimpleBlock()
-    elif t == CSS_SEMICOLON_TOKEN:
-      return result
-    elif t ==  CSS_LBRACE_TOKEN:
-      result.oblock = state.consumeSimpleBlock()
-      return result
-    else:
-      state.reconsume()
-      result.prelude.add(state.consumeComponentValue())
-
-proc consumeDeclaration(state: var CSSParseState): Option[CSSDeclaration] =
-  let t = CSSToken(state.consume())
-  var decl = CSSDeclaration(name: t.value)
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-  if not state.has() or state.curr() != CSS_COLON_TOKEN:
-    return none(CSSDeclaration)
-  discard state.consume()
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-
-  while state.has():
-    decl.value.add(state.consumeComponentValue())
-
-  var i = decl.value.len - 1
-  var j = 2
-  var k = 0
-  var l = 0
-  while i >= 0 and j > 0:
-    if decl.value[i] != CSS_WHITESPACE_TOKEN:
-      dec j
-      if decl.value[i] == CSS_IDENT_TOKEN and k == 0:
-        if CSSToken(decl.value[i]).value.toAsciiLower() == "important":
-          inc k
-          l = i
-      elif k == 1 and decl.value[i] == CSS_DELIM_TOKEN:
-        if CSSToken(decl.value[i]).rvalue == Rune('!'):
-          decl.important = true
-          decl.value.del(l)
-          decl.value.del(i)
-          break
-    dec i
-
-  while decl.value.len > 0 and decl.value[^1] == CSS_WHITESPACE_TOKEN:
-    decl.value.del(decl.value.len - 1)
-  return some(decl)
-
-#> Note: Despite the name, this actually parses a mixed list of declarations
-#> and at-rules, as CSS 2.1 does for @page. Unexpected at-rules (which could be
-#> all of them, in a given context) are invalid and should be ignored by the
-#> consumer.
-#Wow this is ugly.
-proc consumeListOfDeclarations(state: var CSSParseState): seq[CSSParsedItem] =
-  while state.has():
-    let t = state.consume()
-    if t == CSS_wHITESPACE_TOKEN or t == CSS_SEMICOLON_TOKEN:
-      continue
-    elif t == CSS_AT_KEYWORD_TOKEN:
-      state.reconsume()
-      result.add(state.consumeAtRule())
-    elif t == CSS_IDENT_TOKEN:
-      var tempList: seq[CSSParsedItem]
-      tempList.add(CSSToken(t))
-      while state.has() and state.curr() != CSS_SEMICOLON_TOKEN:
-        tempList.add(state.consumeComponentValue())
-
-      var tempState = CSSParseState(at: 0, tokens: tempList)
-      let decl = tempState.consumeDeclaration()
-      if decl.isSome:
-        result.add(decl.get)
-    else:
-      state.reconsume()
-      if state.curr() != CSS_SEMICOLON_TOKEN:
-        discard state.consumeComponentValue()
-
-proc consumeListOfRules(state: var CSSParseState): seq[CSSRule] =
-  while state.at < state.tokens.len:
-    let t = state.consume()
-    if t == CSS_WHITESPACE_TOKEN:
-      continue
-    elif t == CSS_CDO_TOKEN or t == CSS_CDC_TOKEN:
-      if state.top_level:
-        continue
-      else:
-        state.reconsume()
-        let q = state.consumeQualifiedRule()
-        if q.isSome:
-          result.add(q.get)
-    elif t == CSS_AT_KEYWORD_TOKEN:
-      state.reconsume()
-      result.add(state.consumeAtRule())
-    else:
-      state.reconsume()
-      let q = state.consumeQualifiedRule()
-      if q.isSome:
-        result.add(q.get)
-
-proc parseStylesheet(state: var CSSParseState): CSSStylesheet =
-  state.top_level = true
-  result.value.add(state.consumeListOfRules())
-
-proc parseStylesheet(inputStream: Stream): CSSStylesheet =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseStylesheet()
-
-proc parseListOfRules(state: var CSSParseState): seq[CSSRule] =
-  return state.consumeListOfRules()
-
-proc parseListOfRules(inputStream: Stream): seq[CSSRule] =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseListOfRules()
-
-proc parseRule(state: var CSSParseState): CSSRule =
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-  if not state.has():
-    raise newException(SyntaxError, "EOF reached!")
-
-  if state.curr() == CSS_AT_KEYWORD_TOKEN:
-    result = state.consumeAtRule()
-  else:
-    let q = state.consumeQualifiedRule()
-    if q.isSome:
-      result = q.get
-    else:
-      raise newException(SyntaxError, "No qualified rule found!")
-
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-  if state.has():
-    raise newException(SyntaxError, "EOF not reached!")
-
-proc parseRule(inputStream: Stream): CSSRule =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseRule()
-
-proc parseDeclaration(state: var CSSParseState): CSSDeclaration =
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-
-  if not state.has() or state.curr() != CSS_IDENT_TOKEN:
-    raise newException(SyntaxError, "No ident token found!")
-
-  let d = state.consumeDeclaration()
-  if d.isSome:
-    return d.get
-
-  raise newException(SyntaxError, "No declaration found!")
-
-proc parseCSSDeclaration*(inputStream: Stream): CSSDeclaration =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseDeclaration()
-
-proc parseListOfDeclarations(state: var CSSParseState): seq[CSSParsedItem] =
-  return state.consumeListOfDeclarations()
-
-proc parseCSSListOfDeclarations*(cvals: seq[CSSComponentValue]): seq[CSSParsedItem] =
-  var state = CSSParseState()
-  state.tokens = collect(newSeq):
-    for cval in cvals:
-      CSSParsedItem(cval)
-  return state.consumeListOfDeclarations()
-
-proc parseCSSListOfDeclarations*(inputStream: Stream): seq[CSSParsedItem] =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseListOfDeclarations()
-
-proc parseComponentValue(state: var CSSParseState): CSSComponentValue =
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-  if not state.has():
-    raise newException(SyntaxError, "EOF reached!")
-
-  result = state.consumeComponentValue()
-
-  while state.has() and state.curr() == CSS_WHITESPACE_TOKEN:
-    discard state.consume()
-  if state.has():
-    raise newException(SyntaxError, "EOF not reached!")
-
-proc parseCSSComponentValue*(inputStream: Stream): CSSComponentValue =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseComponentValue()
-
-proc parseListOfComponentValues(state: var CSSParseState): seq[CSSComponentValue] =
-  while state.has():
-    result.add(state.consumeComponentValue())
-
-proc parseCSSListOfComponentValues*(inputStream: Stream): seq[CSSComponentValue] =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseListOfComponentValues()
-
-proc parseCommaSeparatedListOfComponentValues(state: var CSSParseState): seq[CSSComponentValue] =
-  while state.has(1):
-    let cvl = state.consumeComponentValue()
-    if cvl != CSS_COMMA_TOKEN:
-      result.add(state.consumeComponentValue())
-
-proc parseCommaSeparatedListOfComponentValues(inputStream: Stream): seq[CSSComponentValue] =
-  var state = CSSParseState()
-  state.tokens = tokenizeCSS(inputStream)
-  return state.parseCommaSeparatedListOfComponentValues()
-
-proc printc*(c: CSSComponentValue) =
-  if c of CSSToken:
-    case CSSToken(c).tokenType:
-    of CSS_FUNCTION_TOKEN, CSS_AT_KEYWORD_TOKEN, CSS_URL_TOKEN:
-      eprint CSSToken(c).tokenType, CSSToken(c).value
-    of CSS_HASH_TOKEN:
-      stderr.write('#' & $CSSToken(c).value)
-    of CSS_IDENT_TOKEN:
-      stderr.write(CSSToken(c).value)
-    of CSS_STRING_TOKEN:
-      stderr.write("\"" & $CSSToken(c).value & "\"")
-    of CSS_DELIM_TOKEN:
-      stderr.write(CSSToken(c).rvalue)
-    of CSS_DIMENSION_TOKEN:
-      eprint CSSToken(c).tokenType, CSSToken(c).nvalue, "unit", CSSToken(c).unit, CSSToken(c).tflagb
-    of CSS_NUMBER_TOKEN:
-      stderr.write($CSSToken(c).nvalue & $CSSToken(c).unit)
-    of CSS_PERCENTAGE_TOKEN:
-      stderr.write($CSSToken(c).nvalue & "%")
-    of CSS_COLON_TOKEN:
-      stderr.write(":")
-    of CSS_WHITESPACE_TOKEN:
-      stderr.write(" ")
-    of CSS_SEMICOLON_TOKEN:
-      stderr.write(";\n")
-    of CSS_COMMA_TOKEN:
-      stderr.write(",")
-    else:
-      eprint CSSToken(c).tokenType
-  elif c of CSSDeclaration:
-    stderr.write(CSSDeclaration(c).name)
-    stderr.write(": ")
-    for s in CSSDeclaration(c).value:
-      printc(s)
-    stderr.write(";\n")
-  elif c of CSSFunction:
-    stderr.write($CSSFunction(c).name & "(")
-    for s in CSSFunction(c).value:
-      printc(s)
-    stderr.write(")")
-  elif c of CSSSimpleBlock:
-    case CSSSimpleBlock(c).token.tokenType
-    of CSS_LBRACE_TOKEN: eprint "{"
-    of CSS_LPAREN_TOKEN: stderr.write("(")
-    of CSS_LBRACKET_TOKEN: stderr.write("[")
-    else: discard
-    for s in CSSSimpleBlock(c).value:
-      printc(s)
-    case CSSSimpleBlock(c).token.tokenType
-    of CSS_LBRACE_TOKEN: eprint "}"
-    of CSS_LPAREN_TOKEN: stderr.write(")")
-    of CSS_LBRACKET_TOKEN: stderr.write("]")
-    else: discard
-
-proc parseCSS*(inputStream: Stream): CSSStylesheet =
-  return inputstream.parseStylesheet()
-
-proc debugparseCSS*(inputStream: Stream) =
-  let ss = inputStream.parseStylesheet()
-  for v in ss.value:
-    if v of CSSAtRule:
-      eprint CSSAtRule(v).name
-    else:
-      for c in CSSQualifiedRule(v).prelude:
-        printc(c)
-    case v.oblock.token.tokenType
-    of CSS_LBRACE_TOKEN: eprint "\n{"
-    of CSS_LPAREN_TOKEN: eprint "("
-    of CSS_LBRACKET_TOKEN: eprint "["
-    else: discard
-    for s in v.oblock.value:
-      printc(s)
-    case v.oblock.token.tokenType
-    of CSS_LBRACE_TOKEN: eprint "\n}"
-    of CSS_LPAREN_TOKEN: eprint ")"
-    of CSS_LBRACKET_TOKEN: eprint "]"
-    else: discard