Skip to content

Commit

Permalink
Merge next branch into main
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Jan 23, 2025
2 parents 6324ac8 + 7b6217f commit f3700bb
Show file tree
Hide file tree
Showing 14 changed files with 68 additions and 57 deletions.
4 changes: 2 additions & 2 deletions src/core/anticipation+aviation-core.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ package anticipation
import aviation.*

package instantApi:
given Timing.Instant is GenericInstant & SpecificInstant as aviationInstant =
given aviationInstant: Timing.Instant is GenericInstant & SpecificInstant =
new GenericInstant with SpecificInstant:
type Self = Timing.Instant
export Timing.Instant.generic.{instant, millisecondsSinceEpoch}

package durationApi:
given Timing.Duration is GenericDuration & SpecificDuration as aviationDuration =
given aviationDuration: Timing.Duration is GenericDuration & SpecificDuration =
new GenericDuration with SpecificDuration:
type Self = Timing.Duration
export Timing.Duration.generic.{duration, milliseconds}
26 changes: 15 additions & 11 deletions src/core/aviation-core.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package aviation

import anticipation.*
import fulminate.*
import prepositional.*
import rudiments.*
import vacuous.*

export Timing.{Instant, Duration}
export Aviation.Date
Expand All @@ -27,27 +29,29 @@ export MonthName.{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}
given realm: Realm = realm"aviation"

package calendars:
given RomanCalendar as julian:
given julian: RomanCalendar:
def leapYear(year: Year): Boolean = year%4 == 0
def leapYearsSinceEpoch(year: Int): Int = year/4

given RomanCalendar as gregorian:
given gregorian: RomanCalendar:
def leapYear(year: Year): Boolean = year%4 == 0 && year%100 != 0 || year%400 == 0
def leapYearsSinceEpoch(year: Int): Int = year/4 - year/100 + year/400 + 1

def now()(using clock: Clock): Instant = clock()
def today()(using clock: Clock, calendar: RomanCalendar, timezone: Timezone): Date = (now() in timezone).date

enum TimeEvent:
case ParseStart
def today()(using clock: Clock, calendar: RomanCalendar, timezone: Timezone): Date =
(now() in timezone).date

given [TextType <: Text] => (Text is Extractable into Int) => TextType is Extractable into Base60 =
case As[Int](value: Base60) => value
case _ => Unset

given (using Unapply[Text, Int]): Unapply[Text, Base60] =
case As[Int](value: Base60) => Some(value)
case _ => None
given [TextType <: Text] => (Text is Extractable into Int) => TextType is Extractable into Base24 =
case As[Int](value: Base24) => value
case _ => Unset

given (using Unapply[Text, Int]): Unapply[Text, Base24] =
case As[Int](value: Base24) => Some(value)
case _ => None
enum TimeEvent:
case ParseStart

extension (inline double: Double)
inline def am: Clockface = ${Aviation.validTime('double, false)}
Expand Down
12 changes: 6 additions & 6 deletions src/core/aviation.Aviation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,20 @@ object Aviation:
halt(m"expected a literal double value")

object Date:
erased given Underlying[Date, Int] as underlying = ###
erased given underlying: Underlying[Date, Int] = ###
def of(day: Int): Date = day

def apply(using cal: Calendar)(year: cal.Year, month: cal.Month, day: cal.Day)
: Date raises DateError =
cal.julianDay(year, month, day)

given Date is Showable as show = d =>
given show: Date is Showable = d =>
given RomanCalendar = calendars.gregorian
t"${d.day.toString.show}-${d.month.show}-${d.year.toString.show}"

given (using Tactic[DateError]) => Decoder[Date] as decoder = parse(_)
given decoder: Tactic[DateError] => Decoder[Date] = parse(_)

given (using RomanCalendar) => Date is Encodable in Text as encodable = date =>
given encodable: RomanCalendar => Date is Encodable in Text = date =>
import hieroglyph.textMetrics.uniform
List
(date.year.toString.tt,
Expand All @@ -80,7 +80,7 @@ object Aviation:

. join(t"-")

inline given Date is Orderable as orderable:
inline given orderable: Date is Orderable:
inline def compare
(inline left: Date,
inline right: Date,
Expand All @@ -91,7 +91,7 @@ object Aviation:

given ordering: Ordering[Date] = Ordering.Int

given (using calendar: Calendar) => Date is Addable as plus:
given plus: (calendar: Calendar) => Date is Addable:
type Result = Date
type Operand = Timespan
def add(date: Date, timespan: Timespan): Date = calendar.add(date, timespan)
Expand Down
5 changes: 3 additions & 2 deletions src/core/aviation.Base24.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ object Base24:
def unapply(value: Int): Option[Base24] =
if value < 0 || value > 23 then None else Some(value.asInstanceOf[Base24])

type Base24 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23
type Base24 =
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21
| 22 | 23
7 changes: 4 additions & 3 deletions src/core/aviation.Base60.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ object Base60:
def unapply(value: Int): Option[Base60] =
if value < 0 || value > 59 then None else Some(value.asInstanceOf[Base60])

type Base60 = 0 | 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
type Base60 =
0 | 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
2 changes: 1 addition & 1 deletion src/core/aviation.Clock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract class Clock():
def apply(): Instant

object Clock:
given Clock as current:
given current: Clock:
def apply(): Instant = Instant.of(System.currentTimeMillis)

def fixed(instant: Instant): Clock = new Clock():
Expand Down
4 changes: 2 additions & 2 deletions src/core/aviation.Horology.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ trait Horology:
def addTertiary(time: Clockface, n: Tertiary): Clockface

object Horology:
given Horology as sexagesimal:
given sexagesimal: Horology:
type Primary = Base24
type Secondary = Base60
type Tertiary = Base60
Expand All @@ -46,4 +46,4 @@ object Horology:
val second: Base60 = Base60(time.second + n)
val minute: Base60 = Base60(time.minute + (time.second + n)/60)
val hour: Base24 = Base24(time.hour + (time.minute + (time.second + n)/60)/60)
Clockface(hour, minute, second)
Clockface(hour, minute, second)
2 changes: 1 addition & 1 deletion src/core/aviation.LocalTime.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import rudiments.*
import java.time as jt

object LocalTime:
given (using RomanCalendar) => LocalTime is GenericInstant as generic =
given generic: RomanCalendar => LocalTime is GenericInstant =
_.instant.millisecondsSinceEpoch

case class LocalTime(date: Date, time: Clockface, timezone: Timezone):
Expand Down
2 changes: 1 addition & 1 deletion src/core/aviation.MonthName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object MonthName:
def unapply(value: Int): Option[MonthName] =
if value < 1 || value > 12 then None else Some(fromOrdinal(value - 1))

given Int is Subtractable as monthOfYear:
given monthOfYear: Int is Subtractable:
type Result = YearMonth
type Operand = MonthName
def subtract(year: Int, month: MonthName) = new YearMonth(year, month)
Expand Down
6 changes: 3 additions & 3 deletions src/core/aviation.Timespan.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import rudiments.*
import symbolism.*

object Timespan:
given Timespan & FixedDuration is GenericDuration & SpecificDuration as genericDuration =
given genericDuration: Timespan & FixedDuration is GenericDuration & SpecificDuration =
new GenericDuration with SpecificDuration:
type Self = Timespan & FixedDuration
def duration(milliseconds: Long): Timespan & FixedDuration =
Expand Down Expand Up @@ -51,7 +51,7 @@ object Timespan:
case StandardTime.Minute => new Timespan(0, 0, 0, 0, n, 0) with FixedDuration
case StandardTime.Second => new Timespan(0, 0, 0, 0, 0, n) with FixedDuration

given (using TimeSystem[StandardTime]) => Timespan is Addable as plus:
given plus: TimeSystem[StandardTime] => Timespan is Addable:
type Result = Timespan
type Operand = Timespan
def add(left: Timespan, right: Timespan): Timespan =
Expand All @@ -63,7 +63,7 @@ object Timespan:
left.minutes + right.minutes,
left.seconds + right.seconds)

given (using TimeSystem[StandardTime]) => Timespan is Subtractable as minus:
given minus: TimeSystem[StandardTime] => Timespan is Subtractable:
type Result = Timespan
type Operand = Timespan

Expand Down
2 changes: 1 addition & 1 deletion src/core/aviation.Timestamp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import errorDiagnostics.stackTraces
object Timestamp:
import calendars.gregorian

given (using Tactic[TimestampError]) => Decoder[Timestamp] = text =>
given Tactic[TimestampError] => Decoder[Timestamp] = text =>
text match
case r"$year([0-9]{4})-$month([0-9]{2})-$day([0-9]{2})T$hour([0-9]{2}):$minute([0-9]{2}):$second([0-9]{2})" =>
tend:
Expand Down
12 changes: 6 additions & 6 deletions src/core/aviation.Timing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ object Timing:

object TaiInstant:
erased given underlying: Underlying[TaiInstant, Long] = ###
given Timing.TaiInstant is GenericInstant as generic:
given generic: Timing.TaiInstant is GenericInstant:
def instant(millisecondsSinceEpoch: Long): Timing.TaiInstant = millisecondsSinceEpoch
def millisecondsSinceEpoch(instant: Timing.TaiInstant): Long = instant

Expand All @@ -43,26 +43,26 @@ object Timing:
erased given underlying: Underlying[Instant, Long] = ###
def of(millis: Long): Instant = millis

given Timing.Instant is GenericInstant as generic:
given generic: Timing.Instant is GenericInstant:
def instant(millisecondsSinceEpoch: Long): Timing.Instant = millisecondsSinceEpoch
def millisecondsSinceEpoch(instant: Timing.Instant): Long = instant

inline given Instant is Orderable as orderable:
inline given orderable: Instant is Orderable:
inline def compare
(inline left: Instant, inline right: Instant, inline strict: Boolean, inline greaterThan: Boolean)
: Boolean =
if left == right then !strict else (left < right)^greaterThan

given ordering: Ordering[Instant] = Ordering.Long

given Instant is Addable by Duration into Instant as plus = new Addable:
given plus: Instant is Addable by Duration into Instant = new Addable:
type Self = Instant
type Result = Instant
type Operand = Duration
def add(instant: Instant, duration: Duration): Instant =
instant + (duration.value/1000.0).toLong

given Instant is Subtractable by Instant into Duration as minus = new Subtractable:
given minus: Instant is Subtractable by Instant into Duration = new Subtractable:
type Self = Instant
type Result = Duration
type Operand = Instant
Expand All @@ -73,7 +73,7 @@ object Timing:
object Duration:
def of(millis: Long): Duration = Quantity(millis/1000.0)

given Timing.Duration is (GenericDuration & SpecificDuration) as generic =
given generic: Timing.Duration is (GenericDuration & SpecificDuration) =
new GenericDuration with SpecificDuration:
type Self = Timing.Duration
def duration(milliseconds: Long): Timing.Duration = Quantity(milliseconds.toDouble)
Expand Down
39 changes: 22 additions & 17 deletions src/core/aviation.Tzdb.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ object Tzdb:
case class Duration(hours: Int, minutes: Int, seconds: Int)

enum Entry:
case Rule(name: Text, from: Int, end: Int, change: MonthDate, time: Time,
save: Duration, letters: Option[Text])
case Rule
(name: Text,
from: Int,
end: Int,
change: MonthDate,
time: Time,
save: Duration,
letters: Option[Text])

case Leap(year: Int, month: MonthName, day: Int, time: Time, addition: Boolean)
case Zone(area: Text, location: Option[Text], info: Trie[ZoneInfo])
case Link(from: Text, to: Text)

case class ZoneInfo(stdoff: Duration, rules: Text, format: Text => Text,
until: Option[Text])
case class ZoneInfo(stdoff: Duration, rules: Text, format: Text => Text, until: Option[Text])

enum MonthDate:
case Last(month: MonthName, day: Weekday)
Expand All @@ -52,25 +58,25 @@ object Tzdb:
val stream2 = stream.or:
abort(TzdbError(TzdbError.Reason.ZoneFileMissing(name), 0))

Source.fromInputStream(stream2).getLines.map(Text(_)).map(_.cut(t"\t").head.lower).to(LazyList)
Source.fromInputStream(stream2).getLines.map(Text(_)).map(_.cut(t"\t").head.lower)
. to(LazyList)

parse(name, lines)

def parse(name: Text, lines: LazyList[Text]): List[Tzdb.Entry] logs TimeEvent raises TzdbError =

def parseDuration(lineNo: Int, str: Text) = str.cut(t":").to(List) match
case As[Int](h) :: Nil => Duration(h, 0, 0)
case As[Int](h) :: As[Int](m) :: Nil => Duration(h, m, 0)
case As[Int](h) :: As[Int](m) :: As[Int](s) :: Nil => Duration(h, m, s)
case As[Base24](h) :: Nil => Duration(h, 0, 0)
case As[Base24](h) :: As[Base60](m) :: Nil => Duration(h, m, 0)
case As[Base24](h) :: As[Base60](m) :: As[Base60](s) :: Nil => Duration(h, m, s)

case other =>
abort(TzdbError(TzdbError.Reason.CouldNotParseTime(other.show), lineNo))

def parseTime(lineNo: Int, str: Text) = str.cut(t":").to(List) match
case As[Int](h) :: r"${As[Int](m)}([0-9]*)s" :: Nil => Time(h, m, 0, 's')
case As[Int](h) :: r"${As[Int](m)}([0-9]*)u" :: Nil => Time(h, m, 0, 'u')
case As[Int](h) :: As[Int](m) :: Nil => Time(h, m, 0, Unset)
case As[Int](h) :: As[Int](m) :: As[Int](s) :: Nil => Time(h, m, s, Unset)
case As[Base24](h) :: r"${As[Base60](m)}([0-9]*)s" :: Nil => Time(h, m, 0, 's')
case As[Base24](h) :: r"${As[Base60](m)}([0-9]*)u" :: Nil => Time(h, m, 0, 'u')
case As[Base24](h) :: As[Base60](m) :: Nil => Time(h, m, 0, Unset)
case As[Base24](h) :: As[Base60](m) :: As[Base60](s) :: Nil => Time(h, m, s, Unset)

case other =>
abort(TzdbError(TzdbError.Reason.CouldNotParseTime(other.show), lineNo))
Expand Down Expand Up @@ -126,7 +132,7 @@ object Tzdb:

def parseRule(lineNo: Int, args: List[Text]): Tzdb.Entry.Rule = args match
case name :: from :: to :: _ :: month :: day :: time :: save :: letters :: _ =>
try throwErrors:
try unsafely:
val end = to match
case t"max" => Int.MaxValue
case t"only" => from.decode[Int]
Expand All @@ -136,6 +142,7 @@ object Tzdb:
val t = parseTime(lineNo, time)
val s = parseDuration(lineNo, save)
Tzdb.Entry.Rule(name, from.decode[Int], end, d, t, s, parseLetters(letters))

catch case err: NumberError =>
abort(TzdbError(TzdbError.Reason.UnexpectedRule, lineNo))

Expand All @@ -156,9 +163,7 @@ object Tzdb:
entries: List[Tzdb.Entry] = Nil,
zone: Option[Tzdb.Entry.Zone] = None)
: List[Tzdb.Entry] =
if lines.isEmpty then
//Log.fine(t"Finished parsing $lineNo lines of $name, and got ${entries.size} entries")
entries ++ zone
if lines.isEmpty then entries ++ zone
else
val line: Text = lines.head.upto(_ == '#')
line.cut(unsafely(r"\s+")).to(List) match
Expand Down
2 changes: 1 addition & 1 deletion src/core/aviation.YearMonth.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ case class YearMonth(year: Int, month: MonthName):
import scala.compiletime.ops.int.*

object YearMonth:
given YearMonth is Subtractable as dayOfMonth:
given dayOfMonth: YearMonth is Subtractable:
type Result = Date
type Operand = Int

Expand Down

0 comments on commit f3700bb

Please sign in to comment.