Skip to content

Commit

Permalink
Fix compile errors
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Jun 9, 2024
1 parent 727baf0 commit ef473a8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 49 deletions.
1 change: 0 additions & 1 deletion src/core/exceptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package xylophone

import rudiments.*
import fulminate.*
import gossamer.*

Expand Down
72 changes: 36 additions & 36 deletions src/core/xmlparser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object XmlInterpolation:

case class CharExtractor(chars: Set[Char]):
val charSet = chars.to(Set)
def unapply(char: Char): Boolean = charSet.has(char)
def unapply(char: Char): Boolean = charSet.contains(char)

case class ParseStateNode(name: Text, namespaces: Set[Text])

Expand All @@ -48,36 +48,36 @@ object XmlInterpolation:
current: Text,
source: Text,
ns: Boolean):

def apply(newContext: ContextType, char: Char) =
copy(context = newContext, current = t"$current$char", offset = offset + 1)

def apply(newContext: ContextType): ParseState = copy(context = newContext, offset = offset + 1, ns = false)
def apply(char: Char): ParseState = copy(offset = offset + 1, current = t"$current$char")
def apply(): ParseState = copy(offset = offset + 1)
def reset: ParseState = copy(current = t"")
def namespace: ParseState = copy(ns = true)
def push: ParseState = copy(stack = ParseStateNode(current, Set()) :: stack, current = t"")

def addNamespace(ns: Text): ParseState =
copy(stack = stack.head.copy(namespaces = stack.head.namespaces + ns) :: stack.tail)

def checkNs: Boolean =
!stack.head.name.has(':') || stack.flatMap(_.namespaces).contains(stack.head.name.cut(t":")(0))
!stack.head.name.contains(":") || stack.flatMap(_.namespaces).contains(stack.head.name.cut(t":")(0))

def rollback(difference: Int): ParseState = copy(offset = offset - difference)

def pop: ParseState throws InterpolationError =
val tag = stack.prim.or:
throw InterpolationError(msg"spurious closing tag: $current", offset - current.length, current.length)

if tag.name == current then copy(stack = stack.tail) else
throw
InterpolationError
(msg"closing tag '$current' does not match expected tag '${tag.name}'",
offset - current.length,
current.length)

given Substitution[XmlInput, Text, "t"] with
def embed(value: Text) = XmlInput.Flat(value)

Expand All @@ -98,7 +98,7 @@ object XmlInterpolation:
def skip(state: ParseState): ParseState = state.context match
case AttributeValue | Body => parse(state, t"")
case AttributeEquals => parse(state, t"\"\"")

case _ =>
throw InterpolationError(msg"a substitution cannot be made in this position")

Expand All @@ -114,139 +114,139 @@ object XmlInterpolation:

case _ =>
throw InterpolationError(msg"a substitution cannot be made in this position")

def complete(state: ParseState): XmlDoc =
if state.stack.nonEmpty then throw InterpolationError(msg"""
expected closing tag: ${state.stack.head.name}
""")

safely(Xml.parse(state.source)).or:
throw InterpolationError(msg"the XML could not be parsed")

def parse(state: ParseState, string: Text): ParseState = string.chars.foldLeft(state.copy(offset = 0)):
case (state@ParseState(_, _, _, _, _, _), char) => state.context match

case InTagName => char match
case TagChar() => state(char)
case ' ' | '\n' | '\r' | '\t' => state.push(InTagBody)

case '/' =>
if state.current.empty then state(ClosingTag) else state(SelfClosingTagName)

case ':' =>
if state.ns then throw InterpolationError(msg"""
the tag name can contain at most one ':' character to indicate a namespace
""", state.offset, 1)
else state(char).namespace

case '>' =>
if state.push.checkNs then state.push(Body)
else throw InterpolationError(
msg"""the tag uses a namespace that has not been declared with an xmlns attribute""")

case _ =>
throw InterpolationError(msg"""not a valid tag name character""", state.offset, 1)

case SelfClosingTagName => char match
case TagChar() => state(char)

case ':' =>
if state.ns then throw
InterpolationError
(msg"the tag name can contain at most one ':' character to indicate a namespace",
state.offset,
1)
else state(char).namespace

case '>' =>
if state.checkNs then state(Body)
else throw
InterpolationError
(msg"the tag uses a namespace that has not been declared with an xmlns attribute")

case _ => throw InterpolationError(msg"expected '>'", state.offset, 1)

case ClosingTag => char match
case TagChar() => state(char)
case '>' => state.pop(Body)
case ' ' | '\n' | '\t' | '\r' => state()

case ':' =>
if state.ns then throw
InterpolationError
(msg"the tag name can contain at most one ':' character to indicate a namespace",
state.offset,
1)
else state(char).namespace

case _ =>
throw InterpolationError(msg"expected '>' or whitespace", state.offset, 1)

case InAttributeName => char match
case TagChar() => state(char)
case ' ' | '\n' | '\r' | '\t' => state(InAttributeName)

case '>' =>
throw InterpolationError(msg"attribute value has not been specified", state.offset, 1)

case '=' =>
if state.current.starts(t"xmlns:") then state.addNamespace(state.current.drop(6))(AttributeEquals)
else state(AttributeEquals)

case ':' =>
if state.ns then throw
InterpolationError
(msg"the attribute name can contain at most one ':' character to indicate a namespace",
state.offset,
1)
else state(char).namespace

case char =>
throw InterpolationError(msg"character $char is not valid in an attribute name", state.offset, 1)

case AttributeEquals => char match
case ' ' | '\n' | '\r' | '\t' => state()
case '"' => state(AttributeValue)
case _ => throw InterpolationError(msg"expected '\"'", state.offset, 1)

case AttributeValue => char match
case '"' => state(InTagBody)
case '&' => state(InAttributeEntity)
case char => state(char)

case InTagBody => char match
case ' ' | '\n' | '\r' | '\t' => state(InTagBody)
case TagChar() => state(InAttributeName, char)
case '/' => state(TagClose)

case '>' =>
if state.checkNs then state(Body)
else throw
InterpolationError
(msg"the tag uses a namespace that has not been declared with an xmlns attribute")

case char =>
throw InterpolationError(msg"character $char is not permitted in a tag name", state.offset)

case TagClose => char match
case '>' => state.pop(Body)
case _ => throw InterpolationError(msg"expected >", state.offset, 1)

case Body => char match
case '<' => state(InTagName)
case '&' => state(InBodyEntity)
case _ => state()

case InBodyEntity => char match
case ';' => state()

case char =>
throw InterpolationError(msg"character $char is not valid in an entity name", state.offset, 1)

case InAttributeEntity => char match
case ';' => state()
case TagChar() => state()

case char =>
throw InterpolationError(msg"character $char is not valid in an entity name", state.offset, 1)

Expand Down
24 changes: 12 additions & 12 deletions src/core/xylophone.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ case class XmlName(name: Text, namespace: Optional[Namespace] = Unset)
sealed trait Xml:
def pointer: List[Int | Text | Unit]
def root: XmlAst.Root

@targetName("add")
infix def + (other: Xml): XmlDoc raises XmlAccessError

Expand All @@ -53,7 +53,7 @@ object Xml:
given show: Show[Xml] = xml =>
safely(printers.compact.print(XmlDoc(XmlAst.Root(Xml.normalize(xml)*)))).or(t"undefined")

given (using enc: Encoding, printer: XmlPrinter[Text]): GenericHttpResponseStream[Xml] with
given (using enc: Encoding, printer: XmlPrinter[Text]) => Xml is GenericHttpResponseStream:
def mediaType: Text = t"application/xml; charset=${enc.name}"
def content(xml: Xml): LazyList[IArray[Byte]] =
LazyList(summon[XmlPrinter[Text]].print(xml).bytes(using charEncoders.utf8))
Expand All @@ -77,7 +77,7 @@ object Xml:
factory.setNamespaceAware(true)
val builder = factory.newDocumentBuilder().nn

val root =
val root =
try
val array = content.bytes(using charEncoders.utf8).mutable(using Unsafe)
builder.parse(ByteArrayInputStream(array)).nn
Expand Down Expand Up @@ -107,15 +107,15 @@ object Xml:
val alias: Optional[Namespace] = getNamespace(att)
XmlName(att.getLocalName.nn.tt, alias) -> att.getTextContent.nn.tt
}.to(Map)

XmlAst.Element(xmlName, children, attributes)

case PROCESSING_INSTRUCTION_NODE =>
XmlAst.ProcessingInstruction(node.getNodeName.nn.tt, node.getTextContent.nn.tt)

case TEXT_NODE =>
XmlAst.Textual(node.getTextContent.nn.tt)

case id =>
XmlAst.Comment(t"unrecognized node $id")

Expand Down Expand Up @@ -158,14 +158,14 @@ extends Xml, Dynamic:
def pointer: XmlPath = (head :: path).reverse
def selectDynamic(tagName: String): XmlFragment = XmlFragment(tagName.tt, head :: path, root)
def applyDynamic(tagName: String)(idx: Int = 0): XmlNode = selectDynamic(tagName).apply(idx)

@targetName("all")
def `*`: XmlFragment = XmlFragment((), head :: path, root)

@targetName("add")
infix def + (other: Xml): XmlDoc raises XmlAccessError =
XmlDoc(XmlAst.Root(Xml.normalize(this) ++ Xml.normalize(other)*))

def as
[ValueType]
(using decoder: XmlDecoder[ValueType])
Expand All @@ -177,10 +177,10 @@ case class XmlNode(head: Int, path: XmlPath, root: XmlAst.Root) extends Xml, Dyn
def applyDynamic(tagName: String)(idx: Int = 0): XmlNode = selectDynamic(tagName).apply(idx)
def attribute(attribute: Text): Attribute = Attribute(this, attribute)
def pointer: XmlPath = (head :: path).reverse

@targetName("all")
def `*`: XmlFragment = XmlFragment((), head :: path, root)

@targetName("add")
infix def + (other: Xml): XmlDoc raises XmlAccessError =
XmlDoc(XmlAst.Root(Xml.normalize(this) ++ Xml.normalize(other)*))
Expand All @@ -192,10 +192,10 @@ case class XmlDoc(root: XmlAst.Root) extends Xml, Dynamic:
def pointer: XmlPath = Nil
def selectDynamic(tagName: String): XmlFragment = XmlFragment(tagName.tt, Nil, root)
def applyDynamic(tagName: String)(idx: Int = 0): XmlNode = selectDynamic(tagName).apply(idx)

@targetName("all")
def `*`: XmlFragment = XmlFragment((), Nil, root)

@targetName("add")
infix def + (other: Xml): XmlDoc raises XmlAccessError =
XmlDoc(XmlAst.Root(Xml.normalize(this) ++ Xml.normalize(other)*))
Expand Down

0 comments on commit ef473a8

Please sign in to comment.