diff --git a/effekt/js/src/main/scala/effekt/context/VirtualModuleDB.scala b/effekt/js/src/main/scala/effekt/context/VirtualModuleDB.scala index c154f20c1..4dbf27700 100644 --- a/effekt/js/src/main/scala/effekt/context/VirtualModuleDB.scala +++ b/effekt/js/src/main/scala/effekt/context/VirtualModuleDB.scala @@ -17,11 +17,9 @@ trait VirtualModuleDB extends ModuleDB { self: Context => * used by Namer to resolve FFI includes */ override def contentsOf(path: String): Option[String] = { - val f = file(module.source.name).parent / path - if (!f.exists) { - None - } else { - Some(f.read) + val parent = file(module.source.name).parent + (parent :: config.includes().map(file)).collectFirst { + case base if (base / path).exists => (base / path).read } } diff --git a/effekt/jvm/src/main/scala/effekt/context/IOModuleDB.scala b/effekt/jvm/src/main/scala/effekt/context/IOModuleDB.scala index bc8781998..4d3ac96ea 100644 --- a/effekt/jvm/src/main/scala/effekt/context/IOModuleDB.scala +++ b/effekt/jvm/src/main/scala/effekt/context/IOModuleDB.scala @@ -13,11 +13,9 @@ trait IOModuleDB extends ModuleDB { self: Context => * used by Namer to resolve FFI includes */ override def contentsOf(path: String): Option[String] = { - val includeFile = file(module.source.name).parent / path - if (!includeFile.exists) { - None - } else { - Some(FileSource(includeFile.toString).content) + val parent = file(module.source.name).parent + (parent :: config.includes().map(file)).collectFirst { + case base if (base / path).exists => FileSource((base / path).toString).content } } diff --git a/effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala b/effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala index 95a7bf26a..1b3209fa3 100644 --- a/effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala +++ b/effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala @@ -262,6 +262,12 @@ lazy val arrays: Builtins = Map( }, ) +lazy val undefined: Builtins = Map( + builtin("effekt::isUndefined[A](A)") { + case Value.Literal(m) :: Nil => Value.Bool(m == null) + }, +) + lazy val refs: Builtins = Map( builtin("ref::ref[T](T)") { case init :: Nil => Value.Ref(Reference(init)) @@ -281,9 +287,6 @@ lazy val regexes: Builtins = Map( builtin("regex::exec(Regex, String)") { case As.Regex(r) :: As.String(str) :: Nil => Value.Literal(r.findFirstMatchIn(str).orNull) }, - builtin("regex::isDefined(RegexMatch)") { - case As.RegexMatch(m) :: Nil => Value.Bool(m != null) - }, builtin("regex::matched(RegexMatch)") { case As.RegexMatch(m) :: Nil => Value.String(m.matched) }, @@ -292,7 +295,7 @@ lazy val regexes: Builtins = Map( }, ) -lazy val builtins: Builtins = printing ++ integers ++ doubles ++ booleans ++ strings ++ arrays ++ refs ++ chars ++ regexes +lazy val builtins: Builtins = printing ++ integers ++ doubles ++ booleans ++ strings ++ arrays ++ refs ++ chars ++ regexes ++ undefined protected object As { object String { diff --git a/examples/chez/libraries.effekt b/examples/chez/libraries.effekt index 8b1d2b532..15b26cd91 100644 --- a/examples/chez/libraries.effekt +++ b/examples/chez/libraries.effekt @@ -12,7 +12,7 @@ import array import mutable/dict import ref -import text/regex +import regex import string def main() = () diff --git a/examples/neg/unbound_type.effekt b/examples/neg/unbound_type.effekt index 160767fb5..48c63cb50 100644 --- a/examples/neg/unbound_type.effekt +++ b/examples/neg/unbound_type.effekt @@ -1,7 +1,7 @@ module examples/pos/lexer import string -import text/regex +import regex effect EOS(): Nothing effect LexerError(msg: String, pos: Position): Nothing diff --git a/examples/pos/simpleparser.effekt b/examples/pos/simpleparser.effekt index 09d7ef5c7..1cd69464d 100644 --- a/examples/pos/simpleparser.effekt +++ b/examples/pos/simpleparser.effekt @@ -1,7 +1,7 @@ module examples/pos/simpleparser import string -import text/regex +import regex effect fail(msg: String): Nothing diff --git a/libraries/chez/common/text/regex.effekt b/libraries/chez/common/text/regex.effekt deleted file mode 100644 index f9bea3ce4..000000000 --- a/libraries/chez/common/text/regex.effekt +++ /dev/null @@ -1,31 +0,0 @@ -module text/regex - -import immutable/cslist - -extern include chez "pregexp.scm" - -extern type Regex - -record Match(matched: String, index: Int) - -extern pure def regex(str: String): Regex = - chez "(pregexp ${str})" - -def exec(reg: Regex, str: String): Option[Match] = { - val matched = reg.unsafeMatchString(str) - if (matched.isUndefined) { None() } - else { Some(Match(matched, reg.unsafeMatchIndex(str))) } -} - -extern pure def unsafeMatchIndex(reg: Regex, str: String): Int = - chez "(let ([m (pregexp-match-positions ${reg} ${str})]) (if m (car (car m)) #f))" - -// we ignore the captures for now and only return the whole match -extern pure def unsafeMatchString(reg: Regex, str: String): String = - chez "(let ([m (pregexp-match ${reg} ${str})]) (if m (car m) #f))" - -extern pure def split(reg: Regex, str: String): CSList[String] = - chez "(pregexp-split ${reg} ${str})" - -// def split(str: String, sep: String): Array[String] = -// toArray(split(sep.regex, str)) \ No newline at end of file diff --git a/libraries/common/effekt.effekt b/libraries/common/effekt.effekt index 2049fb3b8..96fbfac18 100644 --- a/libraries/common/effekt.effekt +++ b/libraries/common/effekt.effekt @@ -667,11 +667,13 @@ extern pure def toInt(n: Byte): Int = extern pure def undefined[A](): A = js "undefined" chez "#f" + vm "effekt::undefined()" /// Is an FFI value undefined? extern pure def isUndefined[A](value: A): Bool = js "(${value} === undefined || ${value} === null)" chez "(eq? ${value} #f)" + vm "effekt::isUndefined[A](A)" // Tuples diff --git a/libraries/common/regex.effekt b/libraries/common/regex.effekt index ca3901bda..077f9409d 100644 --- a/libraries/common/regex.effekt +++ b/libraries/common/regex.effekt @@ -2,44 +2,59 @@ module regex import string +extern include chez "text/pregexp.scm" + extern type Regex record Match(matched: String, index: Int) extern pure def regex(str: String): Regex = js "new RegExp(${str})" + chez "(pregexp ${str})" vm "regex::regex(String)" def exec(reg: Regex, str: String): Option[Match] = { val v = reg.unsafeExec(str) - if (v.isDefined) - Some(Match(v.matched, v.index)) - else + if (v.isUndefined) None() + else + Some(Match(v.matched, v.index)) } extern type RegexMatch // js: { matched: String, index: Int } | undefined // vm: scala.util.matching.Regex.Match | null -extern pure def isDefined(r: RegexMatch): Bool = - js "!!${r}" - vm "regex::isDefined(RegexMatch)" + extern pure def matched(r: RegexMatch): String = js "${r}.matched" + chez "(vector-ref ${r} 0)" vm "regex::matched(RegexMatch)" + extern pure def index(r: RegexMatch): Int = js "${r}.index" + chez "(vector-ref ${r} 1)" vm "regex::index(RegexMatch)" extern js """ -function regex$exec(reg, str) { - var res = reg.exec(str); - if (res === null) { return undefined } - else { return { matched: res[0], index: res.index } } -} + function regex$exec(reg, str) { + var res = reg.exec(str); + if (res === null) { return undefined } + else { return { matched: res[0], index: res.index } } + } +""" + +extern chez """ +(define regex-exec + (lambda (regex str) + (let* ([positions (pregexp-match-positions regex str)] + [match (pregexp-match regex str)]) + (if (and positions match) + (vector (car match) (caar positions)) + #f)))) """ // internals extern io def unsafeExec(reg: Regex, str: String): RegexMatch = js "regex$exec(${reg}, ${str})" + chez "(regex-exec ${reg} ${str})" vm "regex::exec(Regex, String)"